iTranslated by AI
[OAuth 2.0] The Dangers of Careless Implementation: Proper Authorization Code Flow and Security Measures
"Do you want to implement a login feature with OAuth 2.0, but find the flow so complex that you just end up copy-pasting code?" 😰
In reality, if you implement OAuth incorrectly, there is a risk of access tokens leaking or accounts being hijacked. In particular, quite a few older tutorial articles introduce methods that are now deprecated.
In this article, I will explain the mechanism of the "Authorization Code Flow," which is currently the most secure and recommended method, along with implementation patterns you should absolutely avoid.
What is OAuth 2.0?
OAuth 2.0 is a framework for Authorization. It is a mechanism for a "user (resource owner) to grant an application (client) permission to access their data (resource) stored in another service."
Its key feature is the ability to link services safely without entrusting your ID/password to the application.
Roles and Flow
There are four main roles involved in OAuth 2.0.

- Resource Owner: The owner of the data (you)
- Client: The app you want to integrate
- Authorization Server: The server that manages authorization (Google, Twitter, etc.)
- Resource Server: The server that holds the data (API)
Summary: Is That Implementation Okay?
Choosing the wrong flow can lead to vulnerabilities.

| Flow Name | Characteristics | Current Recommendation |
|---|---|---|
| Authorization Code Flow | Performs token exchange on the backend. Tokens are not exposed to the browser. | ⭐️ Recommended (Standard) |
| Implicit Flow | Receives tokens via URL fragments. Risk of remaining in browser history. | ❌ Deprecated |
| Client Credentials | No user involved. Used for server-to-server communication. | Limited Use Cases |
Specific Implementation Points
To enhance security, the following measures are essential.
1. CSRF Protection with the state Parameter
When sending an authorization request, generate a random string (state), store it in the session, and include it in the parameters. When the callback returns, verify that it matches the state you sent. Without this, an attacker could potentially force a user to link their account to one the attacker has prepared.
// 1. At the time of authorization request
const state = generateRandomString();
session.state = state;
res.redirect(`https://auth-server.com/authorize?response_type=code&client_id=MY_ID&state=${state}&...`);
// 2. Upon receiving the callback
if (req.query.state !== session.state) {
throw new Error("State mismatch! CSRF attack detected.");
}
2. Never Leak the Client Secret
You use the client_secret when exchanging an "authorization code" for an "access token." This process must always be performed on the backend server.
If you embed the client_secret in the frontend (such as a SPA or mobile app), it can be easily extracted through reverse engineering.
3. Handling Refresh Tokens
Access tokens have short expiration periods (e.g., 1 hour) and are updated using refresh tokens. If a refresh token is leaked, it allows for persistent unauthorized access, so it requires even stricter management (such as storing it in an HttpOnly Cookie).
Implementation Example: Authorization Code Exchange with Node.js Express
// Image of callback processing
app.get('/callback', async (req, res) => {
const { code, state } = req.query;
// 1. Validate State
if (state !== req.session.state) return res.status(403).send('Invalid state');
// 2. Exchange authorization code for access token (backend communication)
const tokenResponse = await axios.post('https://auth-server.com/token', {
grant_type: 'authorization_code',
code,
redirect_uri: REDIRECT_URI,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET // Keep only on the server-side
});
const { access_token } = tokenResponse.data;
// 3. Access API using access token
// ...
});
Conclusion
OAuth 2.0 is powerful, but it becomes a security hole if not implemented correctly. Instead of just "making it work," choose a recommended flow (especially Authorization Code Flow + PKCE) and implement it after understanding the meaning of each parameter.
To prevent security incidents, using libraries (like NextAuth.js) is one option, but understanding the underlying mechanism is important.
Discussion