oAuth2
- Antonio Linares
- Site Admin
- Posts: 42846
- Joined: Thu Oct 06, 2005 5:47 pm
- Location: Spain
- Has thanked: 181 times
- Been thanked: 124 times
- Contact:
Re: oAuth2
Dear Randal,
In FWH 25.01 there is a new Class TOAuth and a Class TGmail that inherits from TOAuth, both developed by Lailton and a samples\gmail\testgmail.prg example
In FWH 25.01 there is a new Class TOAuth and a Class TGmail that inherits from TOAuth, both developed by Lailton and a samples\gmail\testgmail.prg example
- jose_murugosa
- Posts: 1202
- Joined: Mon Feb 06, 2006 4:28 pm
- Location: Uruguay
- Been thanked: 2 times
- Contact:
Re: oAuth2
Buenos días.
El ejemplo al que haces referencia menciona un archivo readme.rd :
"// USE Your ID and Secret Key. check README.md"
Este archivo no está en la carpeta gmail.
Quisiera saber como obtengo mi ID y Clave Secreta que se menciona, o a que refiere.
Muchas Gracias.
El ejemplo al que haces referencia menciona un archivo readme.rd :
"// USE Your ID and Secret Key. check README.md"
Este archivo no está en la carpeta gmail.
Quisiera saber como obtengo mi ID y Clave Secreta que se menciona, o a que refiere.
Muchas Gracias.
Saludos/Regards,
José Murugosa
"Los errores en programación, siempre están entre la silla, el teclado y la IA!!"
José Murugosa
"Los errores en programación, siempre están entre la silla, el teclado y la IA!!"
- Antonio Linares
- Site Admin
- Posts: 42846
- Joined: Thu Oct 06, 2005 5:47 pm
- Location: Spain
- Has thanked: 181 times
- Been thanked: 124 times
- Contact:
Re: oAuth2
Querido Jose,
Le he enviado un mensaje a Lailton para que nos ayude
Ya que él es el autor
Le he enviado un mensaje a Lailton para que nos ayude

Ya que él es el autor

- cnavarro
- Posts: 6667
- Joined: Wed Feb 15, 2012 8:25 pm
- Location: España
- Has thanked: 9 times
- Been thanked: 12 times
Re: oAuth2
Console Google Cloud
Si no te funciona el anterior enlace, busca Console Google Cloud
En Google Cloud Console, el ID de clave y la clave secreta (o clave API) se utilizan para autenticar las solicitudes a las API de Google. El ID de clave es un identificador único de la clave, mientras que la clave secreta es el secreto que se utiliza para generar tokens de autorización.
Cómo encontrar o crear claves de API (ID y clave secreta):
En la Consola de Google Cloud: Ve a la sección "APIs & Services" y luego a "Credentials".
Crea una clave API: Selecciona "Create Credentials" y luego "API Key".
Acepta la clave API: La clave API recién creada se mostrará en la consola.
ID de cliente de OAuth 2.0: Si necesitas un ID de cliente y un secreto de cliente para OAuth, selecciona "OAuth client ID" en lugar de "API Key".
Cuentas de servicio: Para cuentas de servicio, puedes generar una clave en formato JSON que contiene el ID de cliente y la clave secreta.
Dónde encontrar la clave secreta:
Después de crear una clave API: La clave API se mostrará en el diálogo de creación.
Para claves de cuentas de servicio: Se te proporcionará la clave secreta en el archivo JSON de la clave.
Para OAuth 2.0: El ID de cliente y el secreto de cliente se mostrarán en la consola después de la creación.
Cristobal Navarro
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
Hay dos tipos de personas: las que te hacen perder el tiempo y las que te hacen perder la noción del tiempo
El secreto de la felicidad no está en hacer lo que te gusta, sino en que te guste lo que haces
- Lailton
- Posts: 190
- Joined: Fri Jul 20, 2012 1:49 am
- Location: Brazil
- Has thanked: 2 times
- Been thanked: 15 times
- Contact:
Re: oAuth2
Aqui esta, me parece que Git tiene lo quitado en lo commit 
### How to Create Client ID and Client Secret
1. Open the link: https://console.cloud.google.com/apis/credentials
Log in if you are not already connected.
2. Click on **+ Create Credentials** → **OAuth Client ID**
3. Select **Application Type**: Web Application
4. Enter a **name** (e.g., Company or Software)
5. In **Authorized redirect URIs**, add: `http://localhost:2025`
6. Click **Create**
Once created, the **Client ID** and **Client Secret** will be displayed.
### OAuth Client Created
**Client ID**
**Client Secret**
Save these credentials securely.
It will be used on your PRG
### Data Access Configuration
1. Go to: https://console.cloud.google.com/auth/scopes
2. Click on **Add Scope**, then select the field **Manually add scopes**
3. Enter the following scopes:
4. Click **Add to Table**, then click **Update**
5. Scroll to the bottom of the page and click **Save**
### Verification Process
To remove the **"Unverified App"** warning, fill in all required information and submit your app for verification.
Submit your app for verification here:
https://console.cloud.google.com/auth/verification
That's it! You are ready to continue.
### for x64 copy the Dlls to your exe folder:
Saludos

### How to Create Client ID and Client Secret
1. Open the link: https://console.cloud.google.com/apis/credentials
Log in if you are not already connected.
2. Click on **+ Create Credentials** → **OAuth Client ID**
3. Select **Application Type**: Web Application
4. Enter a **name** (e.g., Company or Software)
5. In **Authorized redirect URIs**, add: `http://localhost:2025`
6. Click **Create**
Once created, the **Client ID** and **Client Secret** will be displayed.
### OAuth Client Created
**Client ID**
Code: Select all | Expand
xxxx-ncpllhkbr7hu8e78fn6lcctvsepsi142.apps.googleusercontent.com
Code: Select all | Expand
xxxx-JEhuFwW6AnGHjfShV-buEkYrirvD
It will be used on your PRG
Code: Select all | Expand
oGmail:setConfig( {;
"client_id" => "xxxx-ncpllhkbr7hu8e78fn6lcctvsepsi142.apps.googleusercontent.com",;
"client_secret" => "xxxx-JEhuFwW6AnGHjfShV-buEkYrirvD",;
"redirect_uri" => "http://localhost:2025/";
} )
### Data Access Configuration
1. Go to: https://console.cloud.google.com/auth/scopes
2. Click on **Add Scope**, then select the field **Manually add scopes**
3. Enter the following scopes:
Code: Select all | Expand
openid
https://www.googleapis.com/auth/userinfo.profile
https://www.googleapis.com/auth/userinfo.email
https://www.googleapis.com/auth/gmail.send
5. Scroll to the bottom of the page and click **Save**
### Verification Process
To remove the **"Unverified App"** warning, fill in all required information and submit your app for verification.
Submit your app for verification here:
https://console.cloud.google.com/auth/verification
That's it! You are ready to continue.
### for x64 copy the Dlls to your exe folder:
Code: Select all | Expand
freeimage64.dll
libcurl.dll
libssl-3-x64.dll
zlib1.dll
Regards,
Lailton Fernando Mariano
Lailton Fernando Mariano
- Otto
- Posts: 6430
- Joined: Fri Oct 07, 2005 7:07 pm
- Has thanked: 48 times
- Been thanked: 15 times
- Contact:
Re: oAuth2
Hello friends,
with the new TGmail class in FWH 25.01, there's now a native way to use Gmail via OAuth2 directly from Harbour – thanks to Lailton for implementing it.
However, I wonder: What practical advantage does this solution offer compared to a simple PowerShell approach that is called via ShellExecute() from the PRG?
In my case, I use PowerShell for sending Gmail via OAuth2 – the entire process is documented in a guide that I’m linking here:
https://winhotel-sandbox.com/docs/gmail ... rshell.pdf
The system runs stably, is easy to maintain, and doesn’t require any MIME or HTTP logic in the PRG. PowerShell is available on every current Windows system, and there’s a wealth of help and examples online. Additionally, the script can be generated, executed, and then deleted at runtime if needed.
I’m aware that we work within a relatively small developer community. That makes it all the more important to use our resources wisely and not reinvent every solution in PRG – especially when something like PowerShell already offers a robust and low-maintenance alternative using built-in system tools.
Another practical advantage: If you convert the script into a .exe using ps2exe, you don't even need to change the execution policy – it runs like a normal Windows program, without the user even realizing that PowerShell is running in the background.
I'm interested in your assessment: What, in your view, speaks in favor of TGmail?
Best regards,
Otto
PowerShell -ExecutionPolicy Bypass -File .\send-gmail-full.ps1
with the new TGmail class in FWH 25.01, there's now a native way to use Gmail via OAuth2 directly from Harbour – thanks to Lailton for implementing it.
However, I wonder: What practical advantage does this solution offer compared to a simple PowerShell approach that is called via ShellExecute() from the PRG?
In my case, I use PowerShell for sending Gmail via OAuth2 – the entire process is documented in a guide that I’m linking here:
https://winhotel-sandbox.com/docs/gmail ... rshell.pdf
The system runs stably, is easy to maintain, and doesn’t require any MIME or HTTP logic in the PRG. PowerShell is available on every current Windows system, and there’s a wealth of help and examples online. Additionally, the script can be generated, executed, and then deleted at runtime if needed.
I’m aware that we work within a relatively small developer community. That makes it all the more important to use our resources wisely and not reinvent every solution in PRG – especially when something like PowerShell already offers a robust and low-maintenance alternative using built-in system tools.
Another practical advantage: If you convert the script into a .exe using ps2exe, you don't even need to change the execution policy – it runs like a normal Windows program, without the user even realizing that PowerShell is running in the background.
I'm interested in your assessment: What, in your view, speaks in favor of TGmail?
Best regards,
Otto
PowerShell -ExecutionPolicy Bypass -File .\send-gmail-full.ps1
Code: Select all | Expand
# =============================================
# PowerShell All-in-One: Gmail API E-Mailversand
# =============================================
# === Konfiguration: Zugangsdaten deiner Google API ===
$client_id = "DEINE_CLIENT_ID"
$client_secret = "DEIN_CLIENT_SECRET"
$redirect_uri = "http://localhost" # Muss mit deiner OAuth2-App übereinstimmen
$tokenFile = "token.json"
# === Deine E-Mail-Daten ===
$to = "empfaenger@example.com"
$subject = "Testmail über Gmail API"
$body = "Hallo! Diese Nachricht wurde mit PowerShell und der Gmail API gesendet."
# === Hilfsfunktionen ===
function Load-Token {
if (Test-Path $tokenFile) {
return Get-Content $tokenFile | ConvertFrom-Json
}
return $null
}
function Save-Token($data) {
$data | ConvertTo-Json | Set-Content -Encoding UTF8 $tokenFile
}
function Get-AccessToken {
$tokenData = Load-Token
if (-not $tokenData -or -not $tokenData.refresh_token) {
Write-Host "🔐 Kein Token gefunden. Starte erstmalige Autorisierung..."
$scope = "https://www.googleapis.com/auth/gmail.send"
$auth_url = "https://accounts.google.com/o/oauth2/v2/auth?" +
"client_id=$client_id&redirect_uri=$redirect_uri&response_type=code" +
"&scope=$scope&access_type=offline&prompt=consent"
Start-Process $auth_url
$code = Read-Host "`n❓ Bitte den Autorisierungscode von Google eingeben"
$response = Invoke-RestMethod `
-Uri "https://oauth2.googleapis.com/token" `
-Method POST `
-Body @{
code = $code
client_id = $client_id
client_secret = $client_secret
redirect_uri = $redirect_uri
grant_type = "authorization_code"
} `
-ContentType "application/x-www-form-urlencoded"
if ($response.access_token) {
$tokenData = @{
access_token = $response.access_token
refresh_token = $response.refresh_token
expires_in = $response.expires_in
obtained_at = (Get-Date).ToString("s")
}
Save-Token $tokenData
Write-Host "✅ Erstes Login erfolgreich. Token gespeichert."
} else {
Write-Host "⛔ Fehler beim Abrufen des Tokens."
exit
}
}
$refresh_token = $tokenData.refresh_token
$response = Invoke-RestMethod `
-Uri "https://oauth2.googleapis.com/token" `
-Method POST `
-Body @{
client_id = $client_id
client_secret = $client_secret
refresh_token = $refresh_token
grant_type = "refresh_token"
} `
-ContentType "application/x-www-form-urlencoded"
if ($response.access_token) {
$tokenData.access_token = $response.access_token
$tokenData.obtained_at = (Get-Date).ToString("s")
Save-Token $tokenData
return $response.access_token
} else {
Write-Host "⛔ Fehler beim Token-Refresh."
exit
}
}
function Send-GmailMail($access_token, $to, $subject, $body) {
$msg = "From: me`r`nTo: $to`r`nSubject: $subject`r`nContent-Type: text/plain; charset=UTF-8`r`n`r`n$body"
$bytes = [System.Text.Encoding]::UTF8.GetBytes($msg)
$base64 = [System.Convert]::ToBase64String($bytes) `
-replace '\+', '-' `
-replace '/', '_' `
-replace '='
$json = @{ raw = $base64 } | ConvertTo-Json -Compress
$response = Invoke-RestMethod `
-Uri "https://gmail.googleapis.com/gmail/v1/users/me/messages/send" `
-Method POST `
-Headers @{ Authorization = "Bearer $access_token" } `
-ContentType "application/json" `
-Body $json
Write-Host "📤 E-Mail wurde gesendet!"
}
# === Hauptablauf ===
$access_token = Get-AccessToken
Send-GmailMail -access_token $access_token -to $to -subject $subject -body $body
- Lailton
- Posts: 190
- Joined: Fri Jul 20, 2012 1:49 am
- Location: Brazil
- Has thanked: 2 times
- Been thanked: 15 times
- Contact:
Re: oAuth2
Hi Otto,
TGmail is a built-in class provided by FWH, which allows you to handle everything within your program and manage the arguments in a “safe” way.
When you expose an external program to perform a task, it’s generally fine if it’s running on your own server, where only you have access.
However, if you’re exposing it on a user’s PC, some data could be exposed, potentially creating vulnerabilities.
That said, both solutions accomplish the same goal. It’s common to find different ways to solve the same problem, but it’s important to evaluate and analyze which approach works best for you.
I don’t see any problem with using either your method or mine—both seem solid.
TGmail is a built-in class provided by FWH, which allows you to handle everything within your program and manage the arguments in a “safe” way.
When you expose an external program to perform a task, it’s generally fine if it’s running on your own server, where only you have access.
However, if you’re exposing it on a user’s PC, some data could be exposed, potentially creating vulnerabilities.
That said, both solutions accomplish the same goal. It’s common to find different ways to solve the same problem, but it’s important to evaluate and analyze which approach works best for you.
I don’t see any problem with using either your method or mine—both seem solid.

Regards,
Lailton Fernando Mariano
Lailton Fernando Mariano
- Otto
- Posts: 6430
- Joined: Fri Oct 07, 2005 7:07 pm
- Has thanked: 48 times
- Been thanked: 15 times
- Contact:
Re: oAuth2
Hello Lailton,
Thank you for your input. I suggested the PowerShell-based approach not because TGmail doesn’t work – but because we, as Harbour developers, will inevitably have to consider PowerShell (and other external tools) more seriously in the future.
The reason is simple: Harbour developer resources are limited, and maintaining internal solutions for everything (like MIME encoding, token handling, API changes) is not scalable. PowerShell, on the other hand, is natively available on all modern Windows systems, well-documented, actively maintained by Microsoft, and easily automatable.
When wrapped securely – with encrypted configs and compiled .exe wrappers – PowerShell becomes a maintainable and robust companion to Harbour. It allows us to focus Harbour on what it does best: core logic and UI, while offloading complex tasks to specialized, scriptable tools.
This isn’t a workaround – it’s a strategic design decision based on sustainability and maintainability. and just because something is embedded in a .prg doesn’t mean it's inherently safer. In fact, access tokens or secrets stored inside a Harbour .exe can be extracted just as easily.
Best regards,
Otto
Thank you for your input. I suggested the PowerShell-based approach not because TGmail doesn’t work – but because we, as Harbour developers, will inevitably have to consider PowerShell (and other external tools) more seriously in the future.
The reason is simple: Harbour developer resources are limited, and maintaining internal solutions for everything (like MIME encoding, token handling, API changes) is not scalable. PowerShell, on the other hand, is natively available on all modern Windows systems, well-documented, actively maintained by Microsoft, and easily automatable.
When wrapped securely – with encrypted configs and compiled .exe wrappers – PowerShell becomes a maintainable and robust companion to Harbour. It allows us to focus Harbour on what it does best: core logic and UI, while offloading complex tasks to specialized, scriptable tools.
This isn’t a workaround – it’s a strategic design decision based on sustainability and maintainability. and just because something is embedded in a .prg doesn’t mean it's inherently safer. In fact, access tokens or secrets stored inside a Harbour .exe can be extracted just as easily.
Best regards,
Otto
- Lailton
- Posts: 190
- Joined: Fri Jul 20, 2012 1:49 am
- Location: Brazil
- Has thanked: 2 times
- Been thanked: 15 times
- Contact:
Re: oAuth2
Thanks for share your idea, it is really interesting and for sure can be useful. how more tools we can have in hand is better.
Like I said, both solutions looks fine for me
Like I said, both solutions looks fine for me

Regards,
Lailton Fernando Mariano
Lailton Fernando Mariano