oAuth2

Post Reply
Randal
Posts: 263
Joined: Mon Oct 24, 2005 8:04 pm

oAuth2

Post by Randal »

Has there been any update on the new oAuth2 class/functions?

I'm using FWH 2023.06 and xHarbour.

Where can I find the HttpPost function?

Can I use Curl with these versions and if so, what do I need?

Thanks,
Randal
User avatar
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

Post by Antonio Linares »

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
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
jose_murugosa
Posts: 1202
Joined: Mon Feb 06, 2006 4:28 pm
Location: Uruguay
Been thanked: 2 times
Contact:

Re: oAuth2

Post by jose_murugosa »

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.
Saludos/Regards,
José Murugosa
"Los errores en programación, siempre están entre la silla, el teclado y la IA!!"
User avatar
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

Post by Antonio Linares »

Querido Jose,

Le he enviado un mensaje a Lailton para que nos ayude :)

Ya que él es el autor :wink:
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
cnavarro
Posts: 6667
Joined: Wed Feb 15, 2012 8:25 pm
Location: España
Has thanked: 9 times
Been thanked: 12 times

Re: oAuth2

Post by cnavarro »

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
User avatar
Lailton
Posts: 190
Joined: Fri Jul 20, 2012 1:49 am
Location: Brazil
Has thanked: 2 times
Been thanked: 15 times
Contact:

Re: oAuth2

Post by Lailton »

Aqui esta, me parece que Git tiene lo quitado en lo commit :D

### 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
**Client Secret**

Code: Select all | Expand

xxxx-JEhuFwW6AnGHjfShV-buEkYrirvD
Save these credentials securely.

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
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:

Code: Select all | Expand

freeimage64.dll
libcurl.dll
libssl-3-x64.dll
zlib1.dll
Saludos
Regards,
Lailton Fernando Mariano
User avatar
Otto
Posts: 6430
Joined: Fri Oct 07, 2005 7:07 pm
Has thanked: 48 times
Been thanked: 15 times
Contact:

Re: oAuth2

Post by Otto »

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

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


User avatar
Lailton
Posts: 190
Joined: Fri Jul 20, 2012 1:49 am
Location: Brazil
Has thanked: 2 times
Been thanked: 15 times
Contact:

Re: oAuth2

Post by Lailton »

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. 8)
Regards,
Lailton Fernando Mariano
User avatar
Otto
Posts: 6430
Joined: Fri Oct 07, 2005 7:07 pm
Has thanked: 48 times
Been thanked: 15 times
Contact:

Re: oAuth2

Post by Otto »

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
User avatar
Lailton
Posts: 190
Joined: Fri Jul 20, 2012 1:49 am
Location: Brazil
Has thanked: 2 times
Been thanked: 15 times
Contact:

Re: oAuth2

Post by Lailton »

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 :)
Regards,
Lailton Fernando Mariano
Post Reply