bin/google-oauth is a small CLI for obtaining and validating Google refresh tokens used by workflow integrations (Gmail, Google Sheets, Google Calendar, Google Translate).
Any time a workflow or client needs to act on behalf of a Google account via OAuth2. The app loads client_id, client_secret, and refresh_token from three separate environment variables scoped by project, and the individual clients use those credentials at runtime.
Typical situations:
- Setting up a new project/integration for the first time.
- Adding a new scope to an existing project (e.g., you started with Gmail and now need Sheets).
- A refresh token expired or was revoked and you need a new one.
- Verifying that stored credentials are still valid.
Before running authorize, make sure the following environment variables are set:
GOOGLE_CLIENT_ID_<PROJECT>— OAuth2 client ID from Google Cloud Console.GOOGLE_CLIENT_SECRET_<PROJECT>— OAuth2 client secret from Google Cloud Console.
These represent the app registration itself and are shared across all scopes for a project.
Each project uses three separate environment variables:
| Variable | Description |
|---|---|
GOOGLE_CLIENT_ID_<PROJECT> |
OAuth2 client ID |
GOOGLE_CLIENT_SECRET_<PROJECT> |
OAuth2 client secret |
GOOGLE_REFRESH_TOKEN_<PROJECT> |
OAuth2 refresh token obtained via bin/google-oauth authorize |
Example for project MYAPP:
export GOOGLE_CLIENT_ID_MYAPP="..."
export GOOGLE_CLIENT_SECRET_MYAPP="..."
export GOOGLE_REFRESH_TOKEN_MYAPP="1//0dx..."Workflows reference the project by name:
ctx.client.gmail(project: "MYAPP")
ctx.client.google_sheets(spreadsheet_id: "...", project: "MYAPP")
ctx.client.google_translate(project: "MYAPP")Starts the interactive OAuth2 flow.
- Verifies
GOOGLE_CLIENT_ID_<PROJECT>andGOOGLE_CLIENT_SECRET_<PROJECT>are set (fails fast if missing). - Prompts for scope selection (or accepts
--scopesdirectly). - Generates an authorization URL and prints it.
- You open the URL in a browser, grant access, and copy the authorization
codefrom the redirect URL. - The CLI exchanges the code for a
refresh_token. - Prints the refresh token. Store it as
GOOGLE_REFRESH_TOKEN_<PROJECT>in your secret backend (e.g., Vault).
Scope selection
If you do not pass --scopes, the CLI prompts you interactively. You can pick scopes one by one, or choose all to select every available scope at once.
bin/google-oauth authorize --project MYAPP
# Interactive menu: pick individual scopes or select 'all'You can also pass scopes directly:
bin/google-oauth authorize --project MYAPP --scopes gmail.readonly,sheets.readonlyAvailable scope aliases can be listed with bin/google-oauth scopes.
Checks whether GOOGLE_CLIENT_ID_<PROJECT>, GOOGLE_CLIENT_SECRET_<PROJECT>, and GOOGLE_REFRESH_TOKEN_<PROJECT> are present, and attempts to fetch an access token from the refresh token. Use this to verify that stored credentials are still valid.
bin/google-oauth status --project MYAPPLists all supported scope aliases and their full Google OAuth2 scope URLs.
bin/google-oauth scopes- The authorization redirect is
http://localhost. The browser will show a connection error after redirect — this is expected. Copy thecodeparameter from the URL. - Keep
client_secretandrefresh_tokenin your secret backend (Vault, 1Password, etc.), never commit them to the repo. - If a refresh token is revoked, simply re-run
authorizefor the same project to get a new one. - Rotating
GOOGLE_CLIENT_SECRET_<PROJECT>only requires updating one env var — the refresh token stays valid.