OAuth 2.0 ve JWT ile Authentication
OAuth 2.0 ve JWT, modern web uygulamalarında authentication standardıdır.
JWT (JSON Web Token)
Structure
header.payload.signature
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIn0.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Node.js Implementation
const jwt = require('jsonwebtoken');
// Token oluştur
function generateToken(user) {
return jwt.sign(
{
id: user.id,
email: user.email,
role: user.role
},
process.env.JWT_SECRET,
{ expiresIn: '7d' }
);
}
// Token doğrula
function verifyToken(token) {
try {
return jwt.verify(token, process.env.JWT_SECRET);
} catch (err) {
throw new Error('Invalid token');
}
}
// Middleware
function authenticate(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'No token provided' });
}
try {
req.user = verifyToken(token);
next();
} catch (err) {
return res.status(401).json({ error: 'Invalid token' });
}
}
OAuth 2.0 Flow
Authorization Code Flow
// 1. Redirect to OAuth provider
app.get('/auth/google', (req, res) => {
const authUrl = `https://accounts.google.com/o/oauth2/v2/auth?` +
`client_id=${CLIENT_ID}&` +
`redirect_uri=${REDIRECT_URI}&` +
`response_type=code&` +
`scope=openid email profile`;
res.redirect(authUrl);
});
// 2. Callback endpoint
app.get('/auth/callback', async (req, res) => {
const { code } = req.query;
// Exchange code for token
const tokenResponse = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
code,
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
redirect_uri: REDIRECT_URI,
grant_type: 'authorization_code'
})
});
const { access_token, id_token } = await tokenResponse.json();
// Get user info
const userResponse = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
headers: { Authorization: `Bearer ${access_token}` }
});
const user = await userResponse.json();
// Create JWT for your app
const appToken = generateToken(user);
res.json({ token: appToken });
});
Refresh Token Pattern
// Login
app.post('/login', async (req, res) => {
const user = await authenticateUser(req.body);
const accessToken = generateToken(user, '15m');
const refreshToken = generateToken(user, '7d');
// Store refresh token in database
await saveRefreshToken(user.id, refreshToken);
res.json({ accessToken, refreshToken });
});
// Refresh endpoint
app.post('/refresh', async (req, res) => {
const { refreshToken } = req.body;
try {
const payload = verifyToken(refreshToken);
const isValid = await validateRefreshToken(payload.id, refreshToken);
if (!isValid) throw new Error('Invalid refresh token');
const newAccessToken = generateToken(payload, '15m');
res.json({ accessToken: newAccessToken });
} catch (err) {
res.status(401).json({ error: 'Refresh token expired' });
}
});
Best Practices
1. Secure Storage
// ❌ localStorage (XSS vulnerable)
localStorage.setItem('token', token);
// ✅ HttpOnly cookie
res.cookie('token', token, {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 7 * 24 * 60 * 60 * 1000
});
2. CSRF Protection
const csrf = require('csurf');
app.use(csrf({ cookie: true }));
3. Rate Limiting
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100
});
app.use('/api/', limiter);
Güvenli authentication sistemleri kurun!