Providers
Google OAuth
Uses the Ahena CLI (beta). Install it with npm install -g @ahena/cli, or prefix commands with npx @ahena/cli. See Installation. The dashboard covers projects, connections, Doctor, the Stack Graph, plans and approvals without it.
Overview
For apps that already have their own accounts and sign-in (a WordPress site, a Rails or Node app with its own user table) and add "Continue with Google" to them. Ahena keeps track of the Google OAuth client each environment uses, checks with Google that the client exists and that your exact redirect URIs are registered, checks that the client secret is stored, and lists the Google Cloud work only you can do, with the exact values. Your app talks to Google directly (Authorization Code flow, in your code); Ahena is never in the sign-in path.
This is not a hosted auth provider, and declaring it never means moving your users anywhere. If your app uses Supabase Auth or Firebase Authentication for sign-in, configure Google there instead.
Package: @ahena/provider-google-oauth · Category: oauth · Config section: oauth
Capabilities: oauth-client (manual), redirect-uri-verification (read-only)
Status: Live verified (read-only, 2026-10-07): Google's discovery document, and Google's answers for a known client with a registered and an unregistered redirect URI and for an unknown client, using Google's public OAuth Playground client. Not live verified with a customer's own client yet. This covers the capabilities and test scope listed here; it doesn't mean every Google sign-in scenario has been tested, and Ahena doesn't call it production-ready. See status definitions.
Connection
Three things, kept apart (the roles in ADR 0003):
| Role | What | Where it lives today |
|---|---|---|
| Management credential | None. Google has no API for OAuth web clients; Ahena checks only through Google's public endpoints. | — |
| Runtime credential | The client secret, GOOGLE_OAUTH_CLIENT_SECRET (name configurable). Your app uses it to exchange sign-in codes. |
Stored in Ahena with ahena env set until ADR 0003's credential model is built. Giving it to your app is manual. |
| Runtime configuration (not secret) | The client ID, and the redirect URIs per environment. | The client ID in the connection (GOOGLE_OAUTH_CLIENT_ID, it's in every Google sign-in URL); redirect URIs in ahena.config.ts. |
Connecting records the client ID for one environment, and Ahena asks Google's public sign-in endpoint whether the client exists.
ahena connect google-oauth -e staging --set GOOGLE_OAUTH_CLIENT_ID=1234-abc.apps.googleusercontent.com
ahena env set staging GOOGLE_OAUTH_CLIENT_SECRET # the client secret: hidden prompt or stdin
Use a separate OAuth client per environment. Doctor warns when production and another
environment share one (ahena.separation.shared_oauth_client), and when they share the same
secret value.
Permissions
None: there's nothing to grant. Every check uses Google's public endpoints
(accounts.google.com): the OpenID discovery document, and a GET to the authorization endpoint
that isn't followed. Nobody signs in, nothing is created, and no consent screen is shown to
anyone. permissionCheck is authentication-only because there is no credential whose
permissions could be read.
Capabilities
export default {
organization: "acme",
project: "leo",
framework: "wordpress", // shapes the instructions for giving the secret to your app
oauth: {
provider: "google-oauth",
clientId: { staging: "1234-stg.apps.googleusercontent.com", production: "1234-prd.apps.googleusercontent.com" },
redirectUris: {
staging: ["https://staging.leo.app/wp-json/myapp/v1/google/callback"],
production: ["https://leo.app/wp-json/myapp/v1/google/callback"],
},
clientSecret: "GOOGLE_OAUTH_CLIENT_SECRET", // its name in Ahena's secret store (this is the default)
runtimeSecret: "MYAPP_GOOGLE_CLIENT_SECRET", // optional: the name your app reads it as
},
};
- Setup steps before connecting. While
oauthis declared but not connected in an environment, Doctor's coverage finding (andahena plan) lists what to do in Google Cloud for that environment: create a "Web application" client, add exactly these redirect URIs, set up the consent screen, store the secret withahena env set, give your app its copy, then connect. - Client check. Google knows the connected client (or answered
invalid_client), and it's the oneahena.config.tsdeclares for the environment. - Redirect URI check. Each declared URI is checked for shape first (https; no localhost outside local and development; no fragment, wildcard, user info or path traversal), then Google is asked whether it's an authorized redirect URI of the client. A refused URI comes with the exact fix.
- Runtime secret stored. Doctor checks that the client secret is stored in Ahena for the
environment (
google-oauth.secret.<name>), by name only. That's all it shows: stored in Ahena is not the same as used by your app, which Doctor reports separately as not verified. - Drift.
ahena.lockrecords the client ID and which declared redirect URIs Google accepts, so a redirect URI removed in Google Cloud shows up inahena drift.
Ahena doesn't generate sign-in code for this provider. What your server side needs is the
Authorization Code flow with PKCE (S256), a single-use state bound to the browser, a nonce, the
code exchanged server side, and the ID token validated against Google's published keys (iss,
aud, exp, nonce, email_verified), with Google's sub as the identity and no automatic
linking to an existing account by e-mail. See Google's
OpenID Connect guide.
Limitations
- Ahena can't create the OAuth client, edit its redirect URIs or set up the consent screen: Google has no public API for web clients. These stay manual, with the exact values.
- Ahena doesn't give the client secret to your app, and can't tell whether your app uses it.
It stores the runtime credential and checks it by name; you put it where your app reads it
(
wp-config.php, your host's environment variables). Doctor reports the app's copy as NOT VERIFIED (google-oauth.runtime_secret) and never claims otherwise. Delivery and fingerprint verification wait on ADR 0003. - The redirect URI check reads where Google's sign-in endpoint redirects. If Google answers in a way Ahena doesn't recognise, the check is a WARNING ("couldn't confirm"), never a pass.
- One OAuth client per environment and provider. Other OAuth providers (GitHub, Microsoft) aren't supported yet.
Manual steps
| Situation | What to do |
|---|---|
| Not connected yet | Follow the steps in Doctor's ahena.coverage.oauth finding: create the Web application client in Google Cloud → Credentials with the listed redirect URIs, set up the consent screen, ahena env set <env> GOOGLE_OAUTH_CLIENT_SECRET, give your app its copy, then ahena connect google-oauth -e <env> --set GOOGLE_OAUTH_CLIENT_ID=…. |
| Redirect URI refused | Open the client in Google Cloud → Credentials and add the URI exactly as shown (scheme, host, path and trailing slash must match). |
| Unknown client | Check the client ID, or create a new client; then reconnect. |
| Rotating the secret | Create a new secret on the client in Google Cloud, ahena env set <env> GOOGLE_OAUTH_CLIENT_SECRET, update your app's copy, then remove the old secret in Google Cloud. |
Doctor checks
| Id | Severity | Meaning |
|---|---|---|
google-oauth.discovery |
PASS / FAIL | Google's OpenID configuration is reachable, names Google as issuer and points only at Google's hosts. |
google-oauth.client_id |
INFO / FAIL | The connected client isn't the one ahena.config.ts declares (FAIL), or none is declared (INFO). |
google-oauth.client |
PASS / WARNING / FAIL | OAuth client exists: VERIFIED with Google (PASS); FAIL with the full setup steps when Google answers invalid_client; WARNING when Google's answer couldn't be read. |
google-oauth.redirect_uris |
WARNING | No redirect URIs declared for this environment. |
google-oauth.redirect.<n> |
PASS / WARNING / FAIL | Redirect URI registered: VERIFIED with Google (PASS) or not registered (FAIL in production, WARNING elsewhere); its shape is checked first. |
google-oauth.secret.<name> |
PASS / FAIL | Runtime secret stored in Ahena for this environment (name only). Not evidence that your app uses it. |
google-oauth.runtime_secret |
INFO | Runtime secret used by your app: NOT VERIFIED. Ahena has no evidence from the app; delivery is manual. |
ahena.coverage.oauth |
FAIL | Declared but not connected: lists the Google Cloud steps with this environment's exact values. |
ahena.separation.shared_oauth_client |
WARNING | Production and another environment use the same OAuth client. |
Disconnect behavior
ahena disconnect google-oauth removes the connection. Ahena held no Google credential, so
there's nothing to revoke; the OAuth client stays in Google Cloud and the secret stays in the
environment's secret store until you remove it (ahena env unset <env> GOOGLE_OAUTH_CLIENT_SECRET). Ahena never deletes anything in
Google Cloud.