Authentication
Sign users in with Strave and authenticate your servers without long-lived secrets.
Strave is an OpenID Connect provider. Your Application can sign users in with their Strave account ("Login with Strave"), act for those users, or act as itself from your server. Every credential ends in a short-lived access token, except API keys.
To get a client ID, create an Application in your developer portal.
Choose a credential
The credential depends on who acts and where your code runs. This table shows which one to use:
| You want to | Use |
|---|---|
| Sign users in, or act for a signed-in user | Login with Strave |
| Call the API from Vercel, GitHub Actions, or GCP | A trusted workload (recommended) |
| Call the API from a script or a bot on a VPS | An API key |
| Exchange authorization codes on your server | A client secret |
Only confidential Applications (Applications with a server) can act as themselves. Public Applications run in a browser, on a phone, or on a desktop. They can't keep a secret, so they only sign users in.
Login with Strave
Login with Strave uses the OAuth 2.1 authorization code flow with S256 PKCE. Most OAuth and OpenID Connect libraries configure themselves from the discovery document:
https://strave.gg/api/auth/.well-known/openid-configurationFollow these steps:
- Add your callback URL under OAuth2 > Redirect URIs.
- Send the user to the authorization endpoint with
openid profile emailand the Strave scopes that you need. - The user signs in and selects Allow. Strave redirects back with a code.
- Exchange the code at the token endpoint. Send
resource=https://strave.gg/api/v2when you also want to call the Public API.
https://strave.gg/api/auth/oauth2/authorize
?response_type=code
&client_id=k3x9q2m7p4w8n1z6b5c0v2d7
&redirect_uri=https://tournaments.example.com/callback
&scope=openid profile email event:read
&state=<random state>
&code_challenge=<S256 PKCE challenge>
&code_challenge_method=S256The token response contains an ID token for the user. Add offline_access to
the scopes to also get a refresh token.
When the user selects Allow, the consent becomes the user's Installation of your Application. There is no separate approval step. The user can remove the access at any time in Settings > Authorized apps. This also deletes the consent and the refresh tokens.
Use Better Auth
If your app uses Better Auth, add Strave with the generic OAuth plugin. The plugin reads the endpoints from the discovery document and handles the state and PKCE values for you.
-
Add
https://your-app.com/api/auth/oauth2/callback/straveas a redirect URI, with your own domain. -
Add the plugin to your Better Auth server. Server Applications also send the client secret.
import { betterAuth } from "better-auth"; import { genericOAuth } from "better-auth/plugins"; export const auth = betterAuth({ plugins: [ genericOAuth({ config: [ { providerId: "strave", clientId: "k3x9q2m7p4w8n1z6b5c0v2d7", clientSecret: process.env.STRAVE_CLIENT_SECRET, authentication: "basic", discoveryUrl: "https://strave.gg/api/auth/.well-known/openid-configuration", scopes: ["openid", "profile", "email", "profile:read"], pkce: true, tokenUrlParams: { resource: "https://strave.gg/api/v2" }, }, ], }), ], }); -
Start the sign-in from your client.
import { createAuthClient } from "better-auth/react"; import { genericOAuthClient } from "better-auth/client/plugins"; export const authClient = createAuthClient({ plugins: [genericOAuthClient()], }); await authClient.signIn.oauth2({ providerId: "strave", callbackURL: "/dashboard", }); -
To call the Public API for the user, get the access token on your server.
const { accessToken } = await auth.api.getAccessToken({ body: { providerId: "strave" }, headers: request.headers, }); const response = await fetch("https://strave.gg/api/v2/users/@me", { headers: { Authorization: `Bearer ${accessToken}` }, });
The OAuth2 section of your Application shows these examples with your client ID and permissions.
Act for an organisation
A user token acts with the user's own permissions. It can act on an organisation or its events only if all of these are true:
- An organisation manager installed your Application on the organisation. Share the install link from the Installations section.
- The user can manage developer Applications in that organisation.
Otherwise, the token only reaches the user and the events that the user plays in.
Act as the Application
A token without a user acts as the Application itself, on the targets that installed it. The owner of the Application is always an installed target.
Trusted workloads
A trusted workload is the recommended way for your servers to authenticate. Your platform (Vercel, GitHub Actions, GitLab CI, Google Cloud, or another OpenID Connect issuer) gives your code a signed identity token. Strave trusts that token instead of a stored secret. There is nothing to store, rotate, or leak.
To add a trusted workload, follow these steps:
- Open Credentials and select Add workload.
- Select your platform and enter the identity of the project, repository, or service account.
- Keep the audience
https://strave.gg/api/auth.
Strave accepts a token only from that issuer and only when every listed claim matches. Then exchange the platform token for a Strave token:
import { getVercelOidcToken } from "@vercel/oidc";
const assertion = await getVercelOidcToken({
audience: "https://strave.gg/api/auth",
});
const response = await fetch("https://strave.gg/api/auth/oauth2/token", {
method: "POST",
body: new URLSearchParams({
grant_type: "client_credentials",
client_id: "k3x9q2m7p4w8n1z6b5c0v2d7",
client_assertion_type:
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
client_assertion: assertion,
resource: "https://strave.gg/api/v2",
}),
});
const { access_token } = await response.json();The Credentials section shows the same example for each platform.
API keys
An API key suits scripts and small bots that don't run on a platform with an identity token. Send the key directly as a bearer token:
Authorization: Bearer strave_sk_…Give each key only the scopes that it needs and an expiry date. Strave shows a key only once and stores only a hash. A revoked key stops working within one minute.
Client secrets
Your server sends a client secret when it exchanges an authorization code or
requests a client_credentials token. An Application can have two secrets at
the same time. To rotate a secret without downtime, follow these steps:
- Select Add secret and copy the new secret.
- Deploy your server with the new secret.
- Revoke the old secret.
Keep client secrets, API keys, and refresh tokens in a server-side secret store. Never put them in URLs, browser bundles, overlay code, logs, or source control.
Send the token
Send the access token or the API key in the Authorization header of each
request:
Authorization: Bearer access_tokenAccess tokens expire after 15 minutes.
How authorization works
Strave accepts a request only if all of these conditions are true:
- The token or key is valid and has the scopes that the route requires.
- The Application is active, and the Installation is active.
- The permission is still an Application permission and the Installation approved it. A permission that the Application removes stops working at once.
- The requested resource belongs to the Installation target.
- For user tokens, the user still has permission on the target.
- The Application owner has the required entitlement and quota.
If a resource is outside the Installation target, Strave returns 404. This
response doesn't reveal whether the resource exists.