Implementing social login using OAuth with providers like GitHub can be a powerful way to improve user experience and security. However, the OAuth flow involves several important steps that developers sometimes misunderstand, especially around how tokens are handled between frontend and backend.
In this post, you’ll walk through the typical OAuth login process using GitHub as an example, understand the roles of the frontend and backend, and highlight critical security considerations.
What is OAuth and Why Use It?
OAuth is an open authorization standard that grants third-party applications limited access to user accounts on services like Google, GitHub, and Facebook—without exposing user credentials. It enables users to log in using their existing accounts without creating new passwords.
The GitHub OAuth Login Flow in a Nutshell
When integrating GitHub OAuth in a React app, you often hear about getting a "code" after the user authorizes your app, then exchanging that code for an access token to fetch user data. But what exactly happens here, and why can’t the frontend do everything?
Step-by-Step Flow
1. User Authorizes Your App on GitHub
- Users click “Login with GitHub” on your React app.
- They are redirected to GitHub’s consent page to grant permission.
- After authorization, GitHub redirects users back with a temporary authorization code.
2. Frontend Receives the Authorization Code
- The React frontend receives this short-lived authorization code (let’s call it
code1
). - This code doesn’t have user info but signals the user’s consent.
3. Frontend Sends Code to Backend
fetch('/auth/github/callback', {
method: 'POST',
body: JSON.stringify({ code: code1 }),
headers: { 'Content-Type': 'application/json' }
});
4. Backend Exchanges Code for Access Token
- Backend uses the code,
client_id
, andclient_secret
to request an access token from GitHub.
const tokenResponse = await axios.post('https://github.com/login/oauth/access_token', {
client_id: process.env.GITHUB_CLIENT_ID,
client_secret: process.env.GITHUB_CLIENT_SECRET,
code: receivedCode1,
}, {
headers: { Accept: 'application/json' }
});
const accessToken = tokenResponse.data.access_token;
5. Backend Requests User Info from GitHub
const userResponse = await axios.get('https://api.github.com/user', {
headers: { Authorization: `Bearer ${accessToken}` }
});
const userData = userResponse.data;
// Process and store user data or create session
6. Backend Creates Session or Issues JWT
- Backend creates a session or issues a signed JWT token encoding user info.
- Sends this token or session ID back to the frontend.
- Frontend uses this on subsequent requests to authenticate the user.
Why Offload Token Exchange to Backend?
-
Client Secret Security: Never expose
client_secret
on the frontend—it’s a private credential. - Token Privacy: Backend keeps access tokens hidden from clients, limiting risk from frontend breaches.
- Control & Revocation: Backend manages session lifecycle, allowing token/session invalidation.
- CORS & Rate Limits: Backend avoids cross-origin and rate limiting issues with third-party APIs.
Summary of Data Flow
Party | What it Receives/Uses | Purpose |
---|---|---|
Frontend React App | Authorization Code (code1 ) |
Signals user permission to backend |
Backend Server | code1 → Access Token | Gets authorized API access |
Backend Server | Access Token | Fetches user data |
Backend Server | User data & session/JWT | Creates session or issues JWT |
Frontend React App | Session cookie or JWT | Authenticates future requests |
Top comments (0)