OAuth 2.0
A complete guide to implementing Login and Sign Up using Deriv's OAuth 2.0 Authorization Code flow with PKCE.
How the flow works
- Generate PKCE — Create a
code_verifier(random string) and derivecode_challenge= BASE64URL(SHA256(code_verifier)). Also generate a randomstatefor CSRF protection. - Redirect to Deriv — Send the user to Deriv's authorization URL with all required parameters.
- User authenticates — Deriv shows either the login or registration form. All login and consent screens are managed by the OAuth provider.
- Redirect back — Deriv redirects the user to your
redirect_uriwith an authorizationcodeandstate. - Verify state — Confirm the returned
statematches what you stored. This prevents CSRF attacks. - Exchange code for token — Your backend sends the
code+code_verifierto Deriv's token endpoint and receives anaccess_token. - Use the token — Make authenticated API calls using the Bearer token.
Before you start
You need:
- A registered OAuth2 client from Deriv with a
client_idand a pre-registeredredirect_uri. - HTTPS enabled on your redirect URL.
- Your app must handle redirects, read the authorization code, and exchange it for tokens.
Step 1: Generate PKCE parameters
What is PKCE?
PKCE (Proof Key for Code Exchange, pronounced “pixy”) prevents authorization code interception attacks. Even if an attacker intercepts the authorization code, they cannot exchange it without the original code_verifier that only your app generated and stored.
Why it works: Only the app that generated the code_verifier can complete the token exchange.
Generating PKCE in JavaScript
// 1. Generate a random code_verifier
const array = crypto.getRandomValues(new Uint8Array(64));
const codeVerifier = Array.from(array)
.map(v => 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~'[v % 66])
.join('');
// 2. Derive the code_challenge
const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(codeVerifier));
const codeChallenge = btoa(String.fromCharCode(...new Uint8Array(hash)))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
// 3. Generate a random state for CSRF protection
const state = crypto.getRandomValues(new Uint8Array(16))
.reduce((s, b) => s + b.toString(16).padStart(2, '0'), '');
// 4. Store code_verifier and state before redirecting
sessionStorage.setItem('pkce_code_verifier', codeVerifier);
sessionStorage.setItem('oauth_state', state);Required authorization request parameters:
- response_type=code
- client_id
- redirect_uri
- scope
- state
- code_challenge + code_challenge_method=S256 (PKCE)
Storage tip
code_verifier and state in sessionStorage before redirecting — they survive the redirect and are automatically cleared when the tab is closed. Clear them from storage immediately after a successful token exchange.Step 2: Redirect the user to the authorization endpoint
Send users to Deriv's OAuth 2.0 authorization endpoint:
https://auth.deriv.com/oauth2/authLogin
Login uses the standard OAuth2 + PKCE parameters with no additions.
Parameters
Login URL
https://auth.deriv.com/oauth2/auth?
response_type=code
&client_id={YOUR_CLIENT_ID} # e.g. app12345
&redirect_uri={YOUR_REDIRECT_URI} # e.g. https://yourapp.com/callback
&scope=trade+account_manage
&state={RANDOM_STATE} # e.g. abc123random
&code_challenge={PKCE_CHALLENGE} # e.g. E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256Also maintaining a Legacy API app?
&app_id=YOUR_LEGACY_APP_ID to the login URL (and sign up URL). Deriv will check whether the user belongs to the old or new platform and route them to the appropriate version of your app.Login URL with legacy app support
https://auth.deriv.com/oauth2/auth?
response_type=code
&client_id={YOUR_CLIENT_ID}
&redirect_uri={YOUR_REDIRECT_URI}
&scope=trade+account_manage
&state={RANDOM_STATE}
&code_challenge={PKCE_CHALLENGE}
&code_challenge_method=S256
&app_id={YOUR_LEGACY_APP_ID} # V1 app ID from legacy-api.deriv.comSign Up
Sign up uses the same base URL and parameters as login, plus one additional required parameter:
Required sign up parameter
Optional partner attribution parameters
The following parameters are all optional and managed in the Partners dashboard. Include them to attribute signups to your partner account. The tracking token parameter has four equivalent names (t, affiliate_token, sidi, ca) — use whichever one appears in your referral link or Partners dashboard.
Which tracking parameter should I use?
t, affiliate_token, sidi, and ca all serve the same purpose. Use the one that appears in your Deriv referral link or in your Partners dashboard — don't include more than one.Sign Up URL
https://auth.deriv.com/oauth2/auth?
response_type=code
&client_id={YOUR_CLIENT_ID} # e.g. app12345
&redirect_uri={YOUR_REDIRECT_URI} # e.g. https://yourapp.com/callback
&scope=trade+account_manage
&state={RANDOM_STATE} # e.g. abc123random
&code_challenge={PKCE_CHALLENGE} # e.g. E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM
&code_challenge_method=S256
&prompt=registration
&t={YOUR_TRACKING_TOKEN} # or: affiliate_token | sidi | ca — use the name from your referral link
&utm_campaign={YOUR_CAMPAIGN} # e.g. dynamicworks
&utm_medium=affiliate
&utm_source={YOUR_AFFILIATE_ID} # e.g. CU303219Important
state parameter on return and generate your code_challenge from a secure random code_verifier. Never reuse these values between requests.Step 3: Handle the callback
Whether the user logged in or signed up, the callback works exactly the same way. After authentication, Deriv redirects to your redirect_uri:
https://yourapp.com/callback?code=AUTHORIZATION_CODE&state=RANDOM_STATEIf something went wrong:
https://yourapp.com/callback?error=access_denied&error_description=User+cancelledYour app must:
- Verify the state — compare the
statefrom the URL with the value you stored before the redirect. If they don't match, abort — it may be a CSRF attack. - Extract the code — read the
codequery parameter.
The authorization code is single-use and expires quickly
Step 4: Exchange code for tokens
Make a POST request from your backend to the token endpoint. Never perform the token exchange from the browser.
POST https://auth.deriv.com/oauth2/tokenRequest body (form-encoded)
grant_type=authorization_code
client_id=YOUR_CLIENT_ID
code=AUTH_CODE_FROM_CALLBACK
code_verifier=YOUR_ORIGINAL_CODE_VERIFIER
redirect_uri=https://your-app.com/callbackcURL example
curl -X POST https://auth.deriv.com/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "client_id=YOUR_CLIENT_ID" \
-d "code=AUTH_CODE" \
-d "code_verifier=YOUR_CODE_VERIFIER" \
-d "redirect_uri=https://your-app.com/callback"Token response
{
"access_token": "ory_at_...",
"expires_in": 3600,
"token_type": "Bearer"
}Step 5: Use the access token in API calls
Include the access token as a Bearer token in the Authorization header for all API calls:
Authorization: Bearer YOUR_ACCESS_TOKENExample
curl -X GET "https://api.derivws.com/trading/v1/options/accounts" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"Quick reference
Where to find your values:
Troubleshooting
Implementation checklist
Login
response_typeiscodeclient_idandredirect_uriare registered with Derivcode_challengeandstateare generated fresh for each requestcode_verifieris stored insessionStoragebefore redirect- Callback verifies
statebefore exchanging the code - Token exchange happens server-side (not in the browser)
code_verifieris cleared from storage after use- If maintaining a legacy app,
app_idis set to your Legacy app ID (optional)
Sign Up (additional)
promptis set toregistration(required)- Tracking token (one of
t,affiliate_token,sidi,ca),utm_source,utm_campaign, andutm_mediumare set if needed — use the parameter name shown in your referral link or Partners dashboard (optional)
Any other questions? Get in touch