Skip to main content
The fullstack app ships with OAuth disabled. Enable providers only after a provider app exists, callback URLs are registered with that provider, and the matching environment variables are set. This page is the operator runbook for milestone A11 in the auth PRD tracker. It covers live-provider verification only. Local deterministic OAuth state, replay, provider mismatch, and unsafe redirect checks are already covered by the development callback bypass smoke tests.

Callback URLs

Use the same public base URL for AUTH_PUBLIC_BASE_URL and every enabled provider callback. Register the exact callback URL with the provider console. Google and Facebook provider consoles require the redirect URI to match what the auth request sends. Apple Sign in with Apple for web requires an absolute return URL with scheme, host, and path; use a real HTTPS domain for Apple live smoke instead of localhost or an IP address.

Environment

Start from examples/fullstack-app/.env.example, keep password login enabled, and enable only the provider being tested.
For Apple, use either a generated client secret from AUTH_APPLE_TEAM_ID, AUTH_APPLE_KEY_ID, and AUTH_APPLE_PRIVATE_KEY, or set AUTH_APPLE_GENERATED_CLIENT_SECRET to a pre-generated client-secret JWT. For HTTPS deployments, keep AUTH_COOKIE_SECURE=true so browser callback and password-login sessions are issued with Secure, HttpOnly, and SameSite=Lax cookie attributes. Local HTTP development can keep it false.

Provider Setup

Shared App Requirements

Use a real HTTPS host before creating provider apps. Provider consoles validate redirect URLs against what the auth stack sends at runtime, so these values must agree exactly: Do not use localhost, 127.0.0.1, or an IP address for live provider smoke. For local development, put the Spin app behind a trusted HTTPS tunnel, or deploy the app to a disposable HTTPS test host. After the provider app is created, copy values into examples/fullstack-app/.env. Keep .env local and uncommitted. The Makefile and the OAuth verification scripts load this file automatically.

Google OAuth Setup

Use Google Cloud Console for the Google provider.
  1. Open the Google Cloud Console and select or create the project that owns the auth stack.
  2. Configure the OAuth consent screen. For early testing, keep the app in a testing state and add the test Google accounts that will complete browser smoke.
  3. Go to APIs & Services > Credentials.
  4. Create an OAuth client ID with application type Web application.
  5. Add this authorized redirect URI exactly:
  6. Save the client and copy the client ID and client secret.
  7. Set these values in examples/fullstack-app/.env:
The auth stack uses Google’s OIDC endpoints from .env.example by default. Override AUTH_GOOGLE_AUTHORIZATION_URL, AUTH_GOOGLE_TOKEN_URL, or AUTH_GOOGLE_JWKS_URL only when Google changes the endpoint or a test environment requires it.

Facebook Login Setup

Use Meta for Developers for the Facebook provider.
  1. Open Meta for Developers and create or select the app that owns Facebook Login.
  2. In the app dashboard, add the Facebook Login product if it is not already enabled.
  3. Open Facebook Login > Settings. If the dashboard uses the newer Use cases navigation, open the authentication/login use case and continue to its Facebook Login settings.
  4. In Client OAuth settings, keep web OAuth enabled and add this value under Valid OAuth Redirect URIs:
  5. Save changes.
  6. Open Settings > Basic and copy the App ID and App Secret.
  7. Set these values in examples/fullstack-app/.env:
For app-review-restricted Facebook apps, test with users that are allowed by the app’s current mode and roles. If Facebook reports a redirect mismatch, copy the callback URL from this page into the provider console again and verify it matches AUTH_FACEBOOK_REDIRECT_URI byte-for-byte.

Apple Sign In Setup

Use Apple Developer Certificates, Identifiers & Profiles for the Apple provider. Apple web login requires a Services ID associated with an app that has Sign in with Apple enabled.
  1. Ensure a primary App ID exists for the app or organization and that Sign in with Apple is enabled for it.
  2. Create or select a Services ID. This Services ID is the OAuth client ID used by the auth stack.
  3. Configure Sign in with Apple for that Services ID.
  4. Select the primary App ID that is related to the website.
  5. Under website URLs, add the HTTPS domain and the return URL:
  6. Create a Sign in with Apple private key, or use an existing one. Record the Team ID, Key ID, and downloaded private key contents.
  7. Set these values in examples/fullstack-app/.env:
Instead of providing AUTH_APPLE_TEAM_ID, AUTH_APPLE_KEY_ID, and AUTH_APPLE_PRIVATE_KEY, you may pre-generate the Apple client-secret JWT and set AUTH_APPLE_GENERATED_CLIENT_SECRET. The generated-secret path is useful when private keys are managed outside the Spin deployment system.

Hook Credentials Into Spin

For local operator smoke, put provider values in examples/fullstack-app/.env. For deployed Spin environments, pass the same values as Spin variables or runtime secrets that map to the variables in spin.production.toml.example. Minimum shared values:
Provider-specific values can be enabled one provider at a time. Start with Google, then Facebook, then Apple. This keeps redirect and token-exchange failures isolated.

Live Smoke

Run one provider at a time first. This keeps callback and credential failures easy to isolate.
Use the public URL that the provider can redirect to. For local development, put the auth stack behind a trusted HTTPS tunnel or deploy the Spin app to a test host. Before starting the live preflight, run the offline credential readiness check. It reports missing variable names and invalid live URL shapes without printing secret values.
Then run the live OAuth preflight against the running Spin app. The Make target and the underlying preflight script run the same readiness check first. Run one provider first, then expand OAUTH_PROVIDERS after the first provider passes.
The preflight checks /api/auth/capabilities, rejects the development callback bypass URL, validates the external HTTPS authorization endpoint, verifies response_type, client_id, redirect_uri, scope, state, and nonce, and checks OAuth state storage evidence when AUTH_SYSTEM_ACCESS_TOKEN is set. It does not replace the browser callback test because provider credentials and user login are still external dependencies. You can print a redacted event-count report after preflight. This does not print provider secrets, tokens, session IDs, or profile payloads.
Then verify:
  1. GET /api/auth/capabilities includes the enabled provider.
  2. /login shows only credentialed, enabled OAuth providers.
  3. Clicking the provider redirects to the provider authorization URL.
  4. Completing provider login returns to /dashboard.
  5. /api/auth/session reports an authenticated session.
  6. GET /api/auth/storage/status with an AAL2 system-administrator bearer token shows: auth_oauth_state_created, auth_oauth_state_consumed, auth_external_identity_linked, and auth_session_issued.
  7. Reusing the same callback URL fails because OAuth state is single-use.
The fastest way to run the browser portion is the interactive browser smoke. It opens Chromium, clicks the configured provider, waits for you to complete the provider login, captures the issued wasi_auth_dev_session cookie, then checks the session and storage evidence automatically. It also replays the exact callback URL in JSON mode and expects a conflict response, proving OAuth state is single-use.
After completing provider login, capture the issued wasi_auth_dev_session cookie from the browser and run the callback evidence check. SESSION_COOKIE may be a bare session ID, wasi_auth_dev_session=<id>, or a full Cookie: header value. EXPECTED_EMAIL is optional but should be set when the provider account is known. This manual path is useful when the interactive browser smoke cannot run on the operator machine.
The callback evidence check verifies /api/auth/session, confirms /dashboard is reachable with the issued session cookie, and checks storage status for OAuth state creation, state consumption, external identity linking, session issuance, and auth projection progress. After callback smoke, run the same evidence report in callback mode to confirm the final event counts and projection checkpoint.
The implementation tracker marks A11 as operator_pending until this live smoke passes for Google, Facebook, and Apple against real provider apps. Do not mark A11 done without the preflight, browser, callback, and evidence commands above.

Failure Checks

  • Provider missing from /api/auth/capabilities: check AUTH_ENABLE_OAUTH, AUTH_<PROVIDER>_ENABLED, and provider credentials.
  • Provider returns redirect mismatch: compare the provider console callback URL with AUTH_<PROVIDER>_REDIRECT_URI.
  • Apple token exchange fails: verify the Services ID, Team ID, Key ID, private key, and client-secret TTL.
  • User lands on an auth error page: inspect /api/auth/storage/status and the Spin component logs before retrying.

References