Authentication

The Spellweave API uses OAuth 2.0 with Authorization Code + PKCE to securely access user data. This guide covers the full authentication flow.

Overview

Your app redirects users to Spellweave to authorize access. After approval, your app receives an authorization code that you exchange for access and refresh tokens.

  1. Your app generates a PKCE code verifier and challenge
  2. User is redirected to Spellweave to log in and consent
  3. Spellweave redirects back with an authorization code
  4. Your server exchanges the code for tokens
  5. Use the access token to call the API

PKCE (Proof Key for Code Exchange)

PKCE is required on all authorization requests. It prevents authorization code interception attacks. Only the S256 method is supported.

Generate PKCE pair
// 1. Generate a random code_verifier (43-128 characters)
const array = new Uint8Array(32);
crypto.getRandomValues(array);
const codeVerifier = btoa(String.fromCharCode(...array))
  .replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");

// 2. Create the code_challenge (SHA-256 hash, base64url-encoded)
const encoder = new TextEncoder();
const digest = await crypto.subtle.digest("SHA-256", encoder.encode(codeVerifier));
const codeChallenge = btoa(String.fromCharCode(...new Uint8Array(digest)))
  .replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");

Authorization Request

Redirect the user to the authorization endpoint with these parameters:

ParameterRequiredDescription
response_typeYesMust be "code"
client_idYesYour app's client ID
redirect_uriYesMust match a registered redirect URI exactly
scopeYesSpace-separated list of scopes
code_challengeYesS256-hashed PKCE code verifier
code_challenge_methodYesMust be "S256"
stateNoRandom string for CSRF protection (recommended)
Example
GET https://public-api.spellweave.app/api/v1/oauth/authorize
  ?response_type=code
  &client_id=sw_abc123...
  &redirect_uri=https://yourapp.com/callback
  &scope=profile:read collections:read decks:read
  &code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
  &code_challenge_method=S256
  &state=random_csrf_string

Token Exchange

After the user approves, they are redirected to your redirect_uri with a code parameter. Exchange it for tokens using a server-side POST:

Request
curl -X POST https://public-api.spellweave.app/api/v1/oauth/token \
  -d "grant_type=authorization_code" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "code=AUTHORIZATION_CODE" \
  -d "redirect_uri=https://yourapp.com/callback" \
  -d "code_verifier=YOUR_ORIGINAL_CODE_VERIFIER"
Response
{
  "access_token": "eyJhbG...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "dGhpcyBpcyBh...",
  "scope": "profile:read collections:read decks:read"
}

Using the Access Token

Include the access token in the Authorization header:

Request
curl https://public-api.spellweave.app/api/v1/me \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"

Refreshing Tokens

Access tokens expire after 1 hour. Use the refresh token to get a new pair without re-prompting the user. Each refresh token is single-use. A new refresh token is returned with every exchange.

Request
curl -X POST https://public-api.spellweave.app/api/v1/oauth/token \
  -d "grant_type=refresh_token" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "refresh_token=YOUR_REFRESH_TOKEN"

Revoking Tokens

Revoke a token when the user logs out of your app or disconnects their Spellweave account:

Request
curl -X POST https://public-api.spellweave.app/api/v1/oauth/revoke \
  -d "token=TOKEN_TO_REVOKE" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET"