Skip to content

OAuth2 quick reference

Everything SweatStack-specific about the OAuth2 flow, on one page. SweatStack is a standard OAuth2 and OpenID Connect provider. If you have a working integration with another platform, it will almost certainly work here unchanged. For the full walk-through, see OAuth2. For the drop-in button that signs users in and onboards new ones in the same step, see Sign in with SweatStack.

Four things that differ from other platforms

  1. PKCE is optional, not required. The plain Authorization Code flow with a client secret is fully supported.
  2. Credentials are self-service. Nobody emails you a client ID or secret. You get them from the app's settings page.
  3. The client secret is not created automatically. You create it in the Secrets section. With PKCE you need no secret at all.
  4. There is no approval queue. Filling in the four required fields makes your app public the moment you save.

Endpoints

Authorization https://app.sweatstack.no/oauth/authorize
Token https://app.sweatstack.no/api/v1/oauth/token
OIDC discovery https://app.sweatstack.no/.well-known/openid-configuration
JWKS https://app.sweatstack.no/.well-known/jwks.json

If your library supports OpenID Connect discovery, point it at the discovery URL. It then configures every endpoint, scope, and signing key itself.

A complete authorization URL (scopes are space-delimited, URL-encoded):

https://app.sweatstack.no/oauth/authorize?response_type=code&client_id={client_id}&redirect_uri={redirect_uri}&scope=data:read%20data:write

Authorization request parameters

Everything GET /oauth/authorize accepts. The first table is standard OAuth2 and OpenID Connect, with the places where SweatStack's behavior differs from the specification called out. The second table is SweatStack's own. Both of its parameters are optional.

Parameter Standard Values Notes
response_type required code Send it, as every client library does. SweatStack does not validate it: code is the only flow.
client_id required your Application ID Also brands the sign-in and consent screens with your app's name.
redirect_uri required a registered redirect URI See Redirect URIs.
scope required space-delimited scopes See Scopes.
state recommended any string Returned to you unchanged on the callback. Use it for CSRF protection.
code_challenge, code_challenge_method PKCE S256 A flow started with a challenge must finish with its verifier.
nonce OIDC, optional any string Echoed in the id_token that comes with the code exchange.
prompt OIDC, optional none, consent, login, select_account Default consent. none skips the consent screen when the user is signed in and has already granted your app these scopes. Where SweatStack differs from the specification: when it cannot skip, it shows the sign-in or consent screen instead of returning login_required, consent_required or interaction_required to your redirect URI. Consent is always shown for a loopback (localhost) redirect, whatever prompt says. login and select_account are accepted and behave as consent.
Parameter Default Values Effect
email_auth_mode enabled enabled, existing_only How the sign-in screen presents email. existing_only reframes it as "Sign in with an existing email account", so a new user self-selects into a wearable sign-in instead. It changes the wording, not the rules: a user who already has an email account signs in as before. Recommended for apps that need wearable data from day one.
integration none garmin_connect, intervals_icu, wahoo Name one provider and SweatStack skips the sign-in chooser: the user goes straight to that provider, and a signed-in user who has not connected it is sent to connect it before consent. One value per request. A misspelled value returns 422. See Send users straight to one provider.

Anything else on the URL is ignored.

Credentials

  • Client ID = the Application ID on the app's settings page. Public. Safe to ship.
  • Client secret = created by you in the Secrets section. Needed only for the flow without PKCE. Treat it like a password. Never ship it to a browser or a device.

Create an app at Settings → API.

Scopes

Space-delimited (RFC 6749 §3.3); commas also accepted.

Scope Grants
data:read Read access to all user data: activities, dailies (including health measures the user entered), and tests. There is no narrower read scope.
data:write Write (and delete) access. Does not grant read. Request data:read too if you need both.
profile Profile information (includes email).
offline_access Issues a refresh token. Required for PKCE clients to get one; client-secret clients always do.

Pushing data in? If your integration uploads activities into SweatStack, request data:write and see Uploading files: FIT and CSV, a per-file 202 response, and source_processed / source_failed webhooks.

PKCE

Supported and recommended, not required. A flow started with a code_challenge must be completed with its code_verifier. There is no downgrade to a secret. A flow started without PKCE uses the client secret.

Redirect URIs

Three accepted types (RFC 8252): claimed https, loopback http (localhost or 127.0.0.1, any port), and private-use custom schemes (com.example.app://oauth/callback, myapp://callback, reverse-DNS not required). https and loopback match by sub-path. Custom schemes match exactly, so register the precise string your app presents. Public plain http:// and URIs with a #fragment are rejected. Details: accepted formats.

Tokens

Token Lifetime
Access token 15 minutes (JWT, RS256).
Refresh token Until the user revokes your app.

On a 401, refresh and retry instead of restarting the OAuth flow. Token errors follow RFC 6749 §5.2: a JSON body with an error code (invalid_grant, invalid_client, invalid_request, and so on).

Going live

Your app is private (only you can connect) until you fill in four fields: description, URL, image, and privacy statement. Anyone else who opens your authorization link, including you on a second account, sees a "still private" page that names their account and lists what's missing. Save the four fields and the app is public immediately: no review, no queue. See Going live.