Skip to content

Authentication

Every request acts for one member, and carries one bearer token in the Authorization header:

GET /v1/me HTTP/1.1
Host: getrefract.app
Authorization: Bearer rfk_…
Who runs the code Use Token lifetime
You, for yourself A personal key Until you revoke it, or the expiry you chose
Your app, for other members Sign in with Refract (OAuth 2.1, PKCE) Access token one hour, refresh token 90 days
A device without a keyboard The device code Same as OAuth

The API is open to a first group of members while it is new. A member outside it cannot create keys or approve apps, and the API refuses tokens issued for them.

A credential carries the scopes the member granted. Each endpoint needs one, named in the reference; a credential without it gets 403 with INSUFFICIENT_SCOPE.

Scope Lets your app
profile:read See the member’s profile: username, display name, avatar.
library:read See the library and the watchlist.
history:read See what the member watched and when.
ratings:read See the member’s ratings.
lists:read See the member’s lists.

The matching :write scopes exist and imply read; the API serves no write yet.

For code that only you run. In the Refract app, open Access and connected apps from the Integrations screen and create a key: name it, pick its scopes, and optionally give it an expiry between 1 and 365 days. The key starts with rfk_, carries a checksum, and is shown once. A member can hold up to 10 keys and revoke any of them from the same screen; a revoked key stops working at once.

Never ship a personal key in an app other people install: it opens your own account.

For apps that other members use. Refract is an OAuth 2.1 authorization server with PKCE (S256 only), refresh token rotation and OpenID Connect.

Register your app in the same Access screen, under your apps. Give it a name and its redirect URIs: https:// addresses, loopback http://127.0.0.1 or http://[::1] for desktop tools, or a reverse-domain scheme for a native app (com.example.app:/callback). Choose a public client (no secret; PKCE protects the exchange) for apps that run on the user’s device, or a confidential client (with a secret you can rotate) for a server.

The flow. Send the member to the authorization endpoint with a fresh PKCE verifier:

https://getrefract.app/api/auth/oauth2/authorize
?response_type=code
&client_id=YOUR_CLIENT_ID
&redirect_uri=https://example.com/callback
&scope=profile:read library:read offline_access
&state=RANDOM_STATE
&code_challenge=BASE64URL_SHA256_OF_VERIFIER
&code_challenge_method=S256
&resource=https://getrefract.app/v1

The member signs in to Refract, sees your app’s name and the scopes in plain words, and approves or refuses. Refract redirects back with code and your state. Check the state, then exchange the code:

Terminal window
curl https://getrefract.app/api/auth/oauth2/token \
-d grant_type=authorization_code \
-d code=THE_CODE \
-d redirect_uri=https://example.com/callback \
-d client_id=YOUR_CLIENT_ID \
-d code_verifier=THE_VERIFIER \
-d resource=https://getrefract.app/v1

The answer holds an access_token for the API (one hour) and, if you asked for offline_access, a refresh_token. Each refresh returns a new refresh token and retires the old one; store the new one before using it. Refresh tokens last 90 days. A member can disconnect your app at any time from their Access screen; your next refresh then fails and your access token stops working when it expires.

Send resource=https://getrefract.app/v1 (RFC 8707) when you ask for tokens: it names the API the token is for.

The device authorization grant (RFC 8628), for devices where typing a password is painful:

  1. Your device asks for a code:
    Terminal window
    curl https://getrefract.app/api/auth/device/code \
    -d client_id=YOUR_CLIENT_ID \
    -d "scope=profile:read library:read offline_access" \
    -d resource=https://getrefract.app/v1
  2. Show the user_code and ask the member to open getrefract.app/device on their phone. They sign in, check the app name and the scopes, and approve.
  3. Meanwhile, poll the token endpoint every interval seconds:
    Terminal window
    curl https://getrefract.app/api/auth/oauth2/token \
    -d grant_type=urn:ietf:params:oauth:grant-type:device_code \
    -d device_code=THE_DEVICE_CODE \
    -d client_id=YOUR_CLIENT_ID
    authorization_pending means keep waiting; slow_down means wait longer between polls.
Document Address
Authorization server metadata https://getrefract.app/.well-known/oauth-authorization-server
OpenID Connect configuration https://getrefract.app/.well-known/openid-configuration
The API’s protected-resource metadata (RFC 9728) https://getrefract.app/.well-known/oauth-protected-resource/v1

A 401 from the API carries a WWW-Authenticate header that points to the protected-resource metadata and names the scope the endpoint needs.