Skip to main content

OAuth2

OAuth2 lets athletes connect their existing Saturday accounts to your platform. Instead of creating new partner-scoped athletes, you can request access to an athlete’s real Saturday profile — with their explicit consent.

When to use OAuth2

Most partners start with API keys. Add OAuth2 when athletes tell you they already have Saturday accounts.

The flow

1

Redirect to authorize

Your app redirects the athlete to Saturday’s authorization page
2

Athlete authenticates

Athlete logs into their Saturday account (or creates one)
3

Athlete consents

Athlete sees what scopes you’re requesting and clicks “Allow”
4

Code redirect

Saturday redirects back to your app with an authorization code
5

Token exchange

Your server exchanges the code for access and refresh tokens
6

API calls

Use the access token as a Bearer token for API requests

Step 1: Generate PKCE challenge

Saturday requires PKCE (Proof Key for Code Exchange) for all OAuth2 flows. Generate a code verifier and challenge:

Step 2: Redirect to authorize

Build the authorization URL and redirect the athlete:

Step 3: Handle the callback

After the athlete consents, Saturday redirects to your redirect_uri with a code:
Always verify the state parameter matches what you sent. This prevents CSRF attacks. If the athlete denies access:

Step 4: Exchange code for tokens

Step 5: Use the access token

The access token is a JWT that contains the partner ID, athlete UID, and granted scopes. Use it as a Bearer token:
The API automatically scopes requests to the athlete who granted consent. You don’t need to pass an athlete_id — it’s in the JWT.

Step 6: Refresh expired tokens

Access tokens expire after 1 hour. Use the refresh token to get a new pair:
Refresh tokens are single-use. Each refresh rotates both the access and refresh token. The old refresh token is immediately invalidated. Always store the new refresh token.

Available scopes

Coach scopes

A coach (Business tier or higher) can additionally request coach scopes. These unlock the Coach API and the coach tools in the Claude connector. A coach’s OAuth token also carries the athlete-self facet — the same token reads the coach’s own athlete data on /v1/athletes/* and their roster on /v1/coach/*; the route decides which applies. When coach scopes are requested, the consent screen discloses that the app will be able to read the coach’s athletes’ fueling data and manage the coach’s alert settings. Request only the scopes you need. Athletes are more likely to consent when the request is minimal.

Client registration

Saturday supports two registration mechanisms:

Client ID Metadata Documents

CIMD is the MCP 2025-11-25 spec’s preferred registration mechanism (draft-ietf-oauth-client-id-metadata-document). Instead of registering, host a JSON document describing your client at a stable HTTPS URL on a domain you control, and pass that URL as your client_id:
Saturday fetches, validates, and caches the document when it first sees your client_id. Requirements:
  • The URL must be https, contain a path, and carry no fragment or userinfo.
  • The document’s client_id field must exactly match the document URL.
  • redirect_uris must be https URLs or loopback (http://localhost / http://127.0.0.1) URIs. Loopback URIs match on any port (RFC 8252).
  • CIMD clients are public clients: token_endpoint_auth_method must be none (or absent), and PKCE is mandatory. Confidential CIMD clients (private_key_jwt) are not supported.
  • Documents are cached per their Cache-Control headers (clamped between 5 minutes and 24 hours), so metadata changes propagate within that window.
Saturday advertises support via "client_id_metadata_document_supported": true in its Authorization Server Metadata — spec-compliant MCP clients (including Claude) select CIMD automatically.

Discovery (remote MCP connectors)

For the Claude connector, clients auto-discover the authorization server — no manual configuration. Saturday serves the standard metadata documents (derived per-environment from the request host): An unauthenticated request to /mcp returns 401 with a WWW-Authenticate: Bearer resource_metadata="…" header pointing at the discovery document, which bootstraps the OAuth handshake. The connector is a public client (PKCE, no client secret) and may use loopback redirects (http://127.0.0.1:<any-port>, RFC 8252) for local CLIs such as Claude Code.

Resource indicators (RFC 8707)

Saturday implements RFC 8707 Resource Indicators — token audience binding, as required by the MCP authorization spec. A client names the resource it intends to use the token with via the resource parameter on the authorize and token requests, using the canonical MCP server URI:
When a resource is supplied, Saturday binds it into the access token’s aud claim, and the MCP endpoint rejects any token whose audience was issued for a different resource. A token minted for Saturday can only be used against Saturday — it cannot be replayed elsewhere. A resource that is malformed (not an absolute URI, or carries a fragment) or names a resource this server does not serve is rejected with invalid_target. On refresh, a resource may match the originally-granted resource but cannot retarget the token.

Error scenarios

Revoking tokens

Athletes can revoke access from their Saturday account settings. Partners can programmatically revoke: