Misc

OAuth via GPALRestAPI - Capturing Google Authorization Codes

How the Handshake Works

When a workflow needs a Google authorization code and no refresh token is stored, GPAL.Credentials opens the auth URL in a browser, then polls /get-access-token on the local listener for up to 60 seconds waiting for the redirect to arrive. The code is cleared immediately on retrieval -- it is single use. If the 60-second window passes with nothing returned, GPAL logs the auth URL and falls back to prompting for a manual paste via the console.

// GPAL.Credentials drives the full flow.

// No manual REST calls needed.

//

// 1. GPAL opens the Google auth URL in a browser.

// 2. User approves. Google redirects to:

// http://localhost:3000/access-token

// 3. GPAL polls /get-access-token for up to

// 60 seconds and collects the code.

// 4. If 60 seconds pass with no code,

// GPAL prints the auth URL and asks the

// user to paste the code manually.

//

// The code is single-use -- cleared on retrieval.

// GPALRestAPI clears it after 5 minutes

// if it is never retrieved at all.

NOTE

In Google Cloud Console under your OAuth client, add http://localhost:3000/access-token to Authorized Redirect URIs. Google will refuse the redirect if this URI is not registered.

The Fallback Listener

Before opening the auth URL, GPAL tries to bind the redirect base URL (http://localhost:3000/ by default) using its own minimal HTTP listener. If GPALRestAPI is already running and owns that prefix, the bind fails quietly and the redirect goes to GPALRestAPI as normal. If nothing is listening, GPAL starts the listener itself on a background thread, serves the same /access-token and /get-access-token endpoints, and shuts it down once the code is collected. The OAuth redirect always has somewhere to land regardless of whether GPALRestAPI is running.

// GPAL checks whether something is already

// listening on the redirect base URL.

//

// If GPALRestAPI IS running:

// it owns the port -- redirect lands there.

//

// If GPALRestAPI is NOT running:

// GPAL binds the same base URL itself via

// LocalAuthCallbackServer.StartIfNeeded().

// Same /access-token and /get-access-token

// endpoints, same behavior.

// Listener is stopped after the code

// is retrieved.

NOTE

GPALRestAPI clears a stored code after 5 minutes and shows a notification if it was never retrieved. This is a cleanup guard, not the effective window -- GPAL only polls for 60 seconds. If the code is not collected in that time, the flow has already fallen back to manual entry.

Exchanging the Code for Tokens

Post the code to Google's token endpoint using the same redirect_uri that was registered. Google returns an access token and a refresh token. Store the refresh token -- once you have it, pass it to GPAL.Credentials and the full browser-based authorization flow never needs to run again. GPAL exchanges the refresh token for a fresh access token automatically on every subsequent workflow run.

// Exchange the code for access + refresh tokens:

string tokens = GPAL.RESTClient

.WithAPIBase("https://oauth2.googleapis.com/")

.WithEndpoint("token")

.WithParameters(new {

code,

client_id = clientId,

client_secret = clientSecret,

redirect_uri = "http://localhost:3000/access-token",

grant_type = "authorization_code"

})

.Execute();

// Parse tokens JSON for access_token,

// refresh_token -- store the refresh token.

NOTE

The interactive browser authorization only runs once per Google account. After you have a refresh token, the workflow is fully automated with no user interaction required.

💬 Ask GPAL