Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/MomenSherif/react-oauth/llms.txt

Use this file to discover all available pages before exploring further.

Cross-site request forgery (CSRF) in the OAuth context means an attacker tricks your app into processing an authorization code that was not initiated by your user. The state parameter is the standard defense: your app sends a value to GitHub, and GitHub echoes it back. If the values don’t match, the response is rejected.

Automatic state generation

By default, useGitHubLogin generates a random state string on every hook render. You do not need to configure anything:
const { initiateGitHubLogin } = useGitHubLogin({
  clientId: 'your-github-client-id',
  redirectUri: 'http://localhost:3000/callback',
  // state is generated automatically
  onSuccess: response => {
    // response.state contains the verified state value
    console.log('Authenticated, state was:', response.state);
  },
  onError: error => { console.error(error); },
});
The generated state is created by concatenating two Math.random().toString(36) substrings, producing a string like "k7x2m9pq3j4nr8t". A new value is produced each time the hook renders (unless you provide your own state).

How state is verified

The hook verifies the state automatically before calling onSuccess:
  1. When initiateGitHubLogin is called, the current state value is included in the GitHub authorization URL as the state query parameter.
  2. After the user authorizes, GitHub redirects the popup to your redirectUri with code and state appended.
  3. The hook extracts both values from the popup URL and compares response.state against the state that was sent.
  4. If they match (or if GitHub did not return a state), onSuccess is called.
  5. If they do not match, the hook calls onError with an OA003 error and does not call onSuccess.
A state mismatch (OA003) means the hook rejected the response before your code ever saw it. Never manually bypass this check.

Custom state parameter

If you need to embed application-specific data in the state (e.g., a redirect path or session ID), pass your own value:
const targetPath = '/dashboard';

const { initiateGitHubLogin } = useGitHubLogin({
  clientId: 'your-github-client-id',
  redirectUri: 'http://localhost:3000/callback',
  state: `myapp-${targetPath}-${Math.random().toString(36).slice(2)}`,
  onSuccess: response => {
    // The hook has already verified state matches before calling onSuccess
    // You can parse your custom data out of response.state
    const parts = response.state?.split('-') ?? [];
    const redirectTo = parts[1]; // "/dashboard"
    console.log('Redirect to:', redirectTo);
  },
  onError: error => { console.error(error); },
});
Even with a custom state, always include a random component to ensure uniqueness per request. A fully predictable state value weakens the CSRF protection.

Verifying state in onSuccess

The hook performs automatic state verification. However, if you use a custom state and want to extract data from it in onSuccess, you can safely access response.state — the hook guarantees it already matched:
onSuccess: response => {
  // At this point the hook has already confirmed:
  // response.state === the state value passed to the hook
  //
  // You can parse custom data without re-checking equality:
  if (response.state?.startsWith('myapp-')) {
    const redirectPath = parseRedirectPath(response.state);
    router.push(redirectPath);
  }
},

What happens on a state mismatch

When the state in GitHub’s callback does not match the value the hook sent, the hook:
  1. Calls onError with an OAuthError where error.code === OAuthErrorCode.STATE_MISMATCH (OA003).
  2. Does not call onSuccess.
  3. Closes the popup.
  4. Resets isLoading to false.
onError: error => {
  if (OAuthError.isOAuthError(error) && error.code === OAuthErrorCode.STATE_MISMATCH) {
    // Log the incident for security review
    securityLogger.warn('OAuth state mismatch detected', { userId: currentUserId });
    // Show a generic error to the user
    setError('Authentication failed. Please try again.');
  }
},

Security best practices

  • Use the auto-generated state unless you have a specific reason to provide your own. It is random and unique per render.
  • Include a random component in any custom state value so it cannot be guessed or reused by an attacker.
  • Treat OA003 as a security event. Log it with enough context to investigate, but show only a generic message to the user.
  • Do not store sensitive data in the state. The state parameter travels through GitHub’s servers and the browser URL bar. It is not secret — it is only unpredictable.