Skip to main content
This guide covers how to implement social login (OAuth) in your web application. Make sure you have configured a social login provider on your backend before proceeding.

OAuth login flow

The social login flow involves three steps:
  1. Redirect — Your app redirects the user to the provider’s login page
  2. Callback — The provider redirects back to your app with a challenge_token
  3. Finalize — Your app sends the challenge_token to complete authentication
When the OAuth provider has verify_email enabled and the IdP returns an email it has not verified, an extra OTP step happens between Callback and Finalize — see Verify email via OTP below.
The entire flow is protected by PKCE (Proof Key for Code Exchange). The SDK generates a unique code_verifier and code_challenge pair for each login attempt, and the challenge_token can only be finalized once. This protects against:
  • Authorization code interception — A stolen challenge_token is useless without the code_verifier, which never leaves the browser
  • Replay attacks — The challenge_token is invalidated after a single use
  • Cross-site request forgery (CSRF) — The server validates that the finalize request matches the original authorization request

Redirect to the provider

Use loginWithOAuth to redirect the user to the provider’s authorization page:
The redirectURI must match the redirect URI configured in your OAuth provider settings.

Handle the callback

When the provider redirects back to your app, extract the challenge_token from the URL and finalize the login:

Verify email via OTP

When the OAuth provider config has verify_email enabled and the IdP returns an unverified email, Auth does not finalize the login on the callback. Instead, the redirect carries status=otp_required alongside the challenge_token, and finalizeOAuthLogin returns:
The OTP has already been sent to email. Your app shows an OTP screen, the user enters the code, and you call checkOTP:
After checkOTP resolves successfully the user is fully logged in — call client.refresh() (or whatever your app uses to load the session) and proceed.
Replace src/App.jsx with:
src/App.jsx