OAuth 2.0

Use OAuth 2.0 with the Authorization Code + PKCE flow to build third-party integrations that act on behalf of Rekall users. OAuth tokens use the rat_ prefix and support granular scopes.

When to Use OAuth

OAuth 2.0 is designed for applications that need to access Rekall on behalf of other users. If you are building a server-side integration for your own account, use API keys instead.

Registering an OAuth App

Before using the OAuth flow, you need to register your application in the Rekall Developer Dashboard.

  1. Go to Settings → OAuth Apps
  2. Click Register New App
  3. Provide your app name, description, and website URL
  4. Add one or more redirect URIs (see Redirect URIs)
  5. Select the default scopes your app will request
  6. Click Create Application

After registration, you will receive a client_id. Since Rekall uses the PKCE flow, no client secret is issued -- this makes it safe for single-page applications and mobile apps.

OAuth App Credentials
{
"client_id": "rkapp_a1b2c3d4e5f6g7h8",
"app_name": "My Agent Platform",
"redirect_uris": [
"https://myapp.com/callback",
"http://localhost:3000/callback"
],
"default_scopes": ["memories:read", "memories:write"]
}

Authorization Code + PKCE Flow

The PKCE (Proof Key for Code Exchange) flow is a secure authorization flow that does not require a client secret. It works in four steps:

1Your app generates a code_verifier and code_challenge
2User is redirected to Rekall authorization page with the challenge
3User approves the request, Rekall redirects back with an authorization code
4Your app exchanges the code + verifier for access and refresh tokens

Step 1: Generate PKCE Parameters

Generate a cryptographically random code_verifier and derive the code_challenge from it using SHA-256:

import crypto from 'crypto';
// Generate a random code verifier (43-128 characters)
const codeVerifier = crypto.randomBytes(32).toString('base64url');
// Derive the code challenge using SHA-256
const codeChallenge = crypto
.createHash('sha256')
.update(codeVerifier)
.digest('base64url');
// Store the code_verifier -- you'll need it in Step 4
// e.g., save to session storage or a server-side session

Step 2: Redirect to Authorization

Redirect the user to the Rekall authorization endpoint with your app details:

Build authorization URL
const authUrl = new URL('https://api.rekall.ai/v1/oauth/authorize');
authUrl.searchParams.set('client_id', 'rkapp_your_client_id');
authUrl.searchParams.set('redirect_uri', 'https://myapp.com/callback');
authUrl.searchParams.set('response_type', 'code');
authUrl.searchParams.set('scope', 'memories:read memories:write entities:read');
authUrl.searchParams.set('code_challenge', codeChallenge);
authUrl.searchParams.set('code_challenge_method', 'S256');
authUrl.searchParams.set('state', generateRandomState()); // CSRF protection
// Redirect the user
window.location.href = authUrl.toString();
ParameterRequiredDescription
client_idYesYour OAuth app client ID
redirect_uriYesMust match a registered redirect URI
response_typeYesMust be "code"
scopeYesSpace-separated list of scopes
code_challengeYesBase64url-encoded SHA-256 hash of code_verifier
code_challenge_methodYesMust be "S256"
stateRecommendedRandom string for CSRF protection

Step 3: Handle the Callback

After the user approves the request, Rekall redirects back to your redirect_uri with an authorization code and the state parameter:

Callback URL
https://myapp.com/callback?code=rkcode_abc123def456&state=your_random_state
// In your callback route handler
export async function GET(request: Request) {
const url = new URL(request.url);
const code = url.searchParams.get('code');
const state = url.searchParams.get('state');
// Verify the state parameter matches what you sent
if (state !== getStoredState()) {
return new Response('Invalid state parameter', { status: 400 });
}
// Proceed to token exchange (Step 4)
const tokens = await exchangeCodeForTokens(code);
// ...
}

Step 4: Exchange Code for Tokens

Exchange the authorization code and your original code_verifier for access and refresh tokens:

const response = await fetch('https://api.rekall.ai/v1/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
grant_type: 'authorization_code',
client_id: 'rkapp_your_client_id',
code: authorizationCode,
redirect_uri: 'https://myapp.com/callback',
code_verifier: storedCodeVerifier,
}),
});
const tokens = await response.json();
// {
// access_token: "rat_abc123...",
// refresh_token: "rrt_def456...",
// token_type: "Bearer",
// expires_in: 3600,
// scope: "memories:read memories:write entities:read"
// }

Access Token Format

OAuth access tokens use the rat_ prefix (Rekall Access Token) and are used identically to API keys:

Token TypePrefixLifetime
Access Tokenrat_1 hour
Refresh Tokenrrt_30 days
Using an OAuth access token
curl https://api.rekall.ai/v1/memories \
-H "Authorization: Bearer rat_abc123def456ghi789"

Refreshing Tokens

Access tokens expire after 1 hour. Use the refresh token to obtain a new access token without requiring the user to re-authorize:

const response = await fetch('https://api.rekall.ai/v1/oauth/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
grant_type: 'refresh_token',
client_id: 'rkapp_your_client_id',
refresh_token: storedRefreshToken, // rrt_...
}),
});
const newTokens = await response.json();
// New access_token (rat_...) and optionally a rotated refresh_token

Refresh Token Rotation

Rekall uses refresh token rotation for security. Each time you use a refresh token, a new refresh token is issued and the old one is invalidated. Always store the latest refresh token.

Scopes in OAuth

When redirecting users to the authorization page, specify the scopes your app needs as a space-separated list. Users will see these scopes and must approve them.

Requesting scopes
// Request only the scopes your app needs
const scopes = [
'memories:read',
'memories:write',
'entities:read',
].join(' ');
authUrl.searchParams.set('scope', scopes);

The access token will only have the scopes that the user approved. If a user denies a scope, the token will be issued without it. Always check the scope field in the token response to see which scopes were granted. See the full list of available scopes.

Redirect URIs

Redirect URIs must be registered in your OAuth app settings before they can be used. Rekall enforces exact-match validation to prevent open redirect attacks.

check_circle

Production

https://myapp.com/callback
check_circle

Local Development

http://localhost:3000/callback
check_circle

Custom Scheme (Mobile)

myapp://callback

Exact Match

Redirect URIs are matched exactly, including the path, query string, and fragment. https://myapp.com/callback and https://myapp.com/callback/ (with trailing slash) are treated as different URIs.

Error Handling

OAuth errors are returned as query parameters on the redirect URI or as JSON responses from the token endpoint:

Error CodeDescription
invalid_clientUnknown or invalid client_id
invalid_redirect_uriRedirect URI not registered
invalid_scopeRequested scope is not allowed
invalid_grantAuthorization code is expired or used
invalid_pkcecode_verifier does not match challenge
access_deniedUser denied the authorization request
Error response from token endpoint
{
"error": "invalid_grant",
"error_description": "The authorization code has expired. Codes are valid for 10 minutes.",
"error_uri": "https://docs.rekall.ai/authentication/oauth#error-handling"
}
Rekall
rekall