Fix GitHub OAuth Errors
Updated April 2026
Reading this article? Verify your fix in real-time. Debug your GitHub OAuth error → OAuthFixer
GitHub OAuth has two systems — OAuth Apps and GitHub Apps — with different capabilities and configurations. Most errors come from wrong callback URL registration, expired authorization codes, or scope mismatches.
OAuth App vs GitHub App — which to use
| OAuth App | GitHub App | |
|---|---|---|
| Acts as | A user | Itself (bot identity) |
| Access | User's resources | Installation resources |
| Best for | Sign in with GitHub, user data access | CI/CD, repo automation |
| PKCE support | ✅ Yes (recommended) | ✅ Yes |
Common error 1 — redirect_uri_mismatch
# GitHub OAuth App settings: # github.com → Settings → Developer Settings → OAuth Apps → Your App # Authorization callback URL must EXACTLY match your redirect_uri # Wrong Authorization callback URL: https://yourapp.com/ # trailing slash redirect_uri in code: https://yourapp.com/callback # no match # Right — both must match exactly Authorization callback URL: https://yourapp.com/callback redirect_uri in code: https://yourapp.com/callback
Common error 2 — code expired
GitHub authorization codes expire after 10 minutes. Exchange the code immediately after the redirect:
// callback page — exchange immediately
const { code } = new URLSearchParams(window.location.search);
if (code) { // Do this NOW — do not wait, do not store the code const tokens = await exchangeCodeForToken(code);
}
Common error 3 — scope not granted
# Request scopes in the authorization URL
const authUrl = "https://github.com/login/oauth/authorize?" + new URLSearchParams({ client_id: CLIENT_ID, redirect_uri: "https://yourapp.com/callback", scope: "user:email repo", // request what you need state: generateState(),
});
Token exchange — must be server-side
# GitHub token exchange requires client_secret
# NEVER do this in browser-side JavaScript
# Server-side (Node.js)
const response = await fetch("https://github.com/login/oauth/access_token", { method: "POST", headers: { "Accept": "application/json", "Content-Type": "application/json", }, body: JSON.stringify({ client_id: process.env.GITHUB_CLIENT_ID, client_secret: process.env.GITHUB_CLIENT_SECRET, code: authorizationCode, redirect_uri: "https://yourapp.com/callback", }),
});
const { access_token } = await response.json();
PKCE with GitHub (recommended for SPAs)
# GitHub supports PKCE for OAuth Apps — use it for SPAs
const authUrl = "https://github.com/login/oauth/authorize?" + new URLSearchParams({ client_id: CLIENT_ID, code_challenge: challenge, code_challenge_method: "S256", redirect_uri: "https://yourapp.com/callback",
}); Debug your GitHub OAuth error → OAuthFixer