OAuth

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 AppGitHub App
Acts asA userItself (bot identity)
AccessUser's resourcesInstallation resources
Best forSign in with GitHub, user data accessCI/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