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. A web application client matches the redirect exactly, port included, which is why GPAL never moves the listener to a different port. Use a different port by all means, but change it in both places: GoogleRestRedirectUri and the console.

Where the Token Lands

The provider only redirects to the URI registered with it, so the address that catches the token is not a choice GPAL makes: it is the authority of GoogleRestRedirectUri, http://localhost:3000/ by default, read from credentialsConfig.json beside the exe. Before opening the auth URL, GPAL tries to bind that address with its own minimal listener, which serves the same access-token and get-access-token endpoints on a background thread and shuts down once the code is collected. If the bind fails then something already owns the port, and GPAL asks it whether it is GPALRestAPI by calling its status endpoint, waiting one second at most. If it answers, it catches the redirect as normal. If it does not, GPAL reports an error rather than listening somewhere else, because a redirect the provider never agreed to would not arrive anyway. Whichever caught it is readable afterwards as GPAL.OAuthTokenUrl.

// 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 scans upward from 3000, so the first one on a machine takes it, which is why the usual case is that the GPALRestAPI your own browser launched is already sitting on the registered address. A second instance pushed to another port does not catch redirects, and cannot: there is one registered address, so two workflows doing OAuth at the same moment on one machine will collide.

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