OAuth tokens authenticate users against the Dashboard API on
app.photon.codes. The Spectrum API on spectrum.photon.codes uses per-project HTTP Basic credentials instead; the two credential systems are separate and not interchangeable.Endpoints
Discovery
Because the issuer contains a path component (/api/auth), the metadata documents live at the RFC 8414 §3.1 path-insertion URLs — the issuer’s path goes after the well-known segment:
/.well-known/openid-configuration to the issuer or probe the domain root — both of those 404 here, so configure the discovery URL (or the individual endpoints) explicitly in that case.
Create an OAuth app
In the dashboard, open Developer → Apps and create an app. You’ll choose:- Name, logo, homepage — shown to users on the consent screen.
- Redirect URIs — an exact-match allowlist. The
redirect_uriin your authorization request must match one of these character for character. - Client type — confidential for server-side apps that can keep a secret, or public for native and browser-based apps that can’t. Public clients get no secret and rely on PKCE alone.
- Scopes — the maximum set your app may request. Authorization requests for scopes outside this set are rejected with
invalid_scope.
Authorization code flow
PKCE with theS256 challenge method is required for every client, confidential ones included. plain is not accepted.
1
Generate a PKCE verifier and challenge
2
Send the user to the authorization endpoint
scope is a space-separated list (URL-encoded). The user signs in to Photon, reviews the requested scopes on the consent screen, and on approval is redirected to your redirect_uri with code and your state in the query string. Verify state matches what you sent before using the code.3
Exchange the code for tokens
client_secret in the body as shown, or with HTTP Basic (client_id:client_secret) — both are accepted. Public clients omit the secret.id_token is only present when openid was granted, and refresh_token only when offline_access was granted.4
Call the Dashboard API
401. A valid token missing the scope an endpoint requires returns 403 with insufficient_scope: <scope> in the message.Refresh tokens
Request theoffline_access scope to receive a refresh token, then exchange it when the access token expires:
Scopes
Access-token lifetimes
Access tokens live 1 hour by default. Sensitive scopes shorten that:billing:write tokens live 5 minutes, and every other :write scope caps the token at 15 minutes. When one token carries several scopes, the shortest lifetime wins — a token with projects:read and projects:write expires after 15 minutes. Apps that hold write scopes should request offline_access and refresh rather than treating the access token as long-lived.
OpenID Connect
With theopenid scope granted, the token response includes an id_token and the UserInfo endpoint returns the user’s claims:
id_token is a JWT signed with EdDSA (Ed25519) — verify it against the JWKS endpoint, and make sure your JWT library supports EdDSA before relying on local verification. Available claims include sub, email, email_verified, name, and picture, gated by the profile and email scopes.
Revoking access
Apps can revoke a token they hold:Limitations
- No machine-to-machine tokens. The
client_credentialsgrant is not supported — every access token represents a user who went through the consent flow. For server-to-server project automation, use the Spectrum API’s project credentials instead. - No dynamic client registration. The discovery document advertises a
registration_endpoint, but programmatic registration is disabled — create apps in the dashboard. S256only. TheplainPKCE challenge method is rejected, and PKCE cannot be skipped.