OAuth2 Implementation


OAuth2 Fundamentals

OAuth2 is the industry-standard protocol for authorization. It enables third-party applications to obtain limited access to user resources without exposing credentials.

Grant Types

Authorization Code Grant (with PKCE)

The recommended flow for public clients:




// PKCE code challenge generation


const crypto = require("crypto");




function generatePKCE() {


const verifier = crypto.randomBytes(32)


.toString("base64url");


const challenge = crypto.createHash("sha256")


.update(verifier)


.digest("base64url");




return { verifier, challenge };


}




// Authorization request


const { verifier, challenge } = generatePKCE();


const authUrl = `https://auth.example.com/authorize?


response_type=code&


client_id=app123&


redirect_uri=https://app.example.com/callback&


code_challenge=${challenge}&


code_challenge_method=S256&


scope=openid%20profile`;




// Token exchange


async function exchangeCode(code, verifier) {


const resp = await fetch("https://auth.example.com/token", {


method: "POST",


headers: { "Content-Type": "application/x-www-form-urlencoded" },


body: new URLSearchParams({


grant_type: "authorization_code",


code: code,


client_id: "app123",


code_verifier: verifier,


redirect_uri: "https://app.example.com/callback"


})


});


return resp.json();


}





Client Credentials Grant

For server-to-server communication:




import requests




def get_client_credentials_token(client_id, client_secret, scope):


resp = requests.post(


"https://auth.example.com/token",


data={


"grant_type": "client_credentials",


"client_id": client_id,


"client_secret": client_secret,


"scope": scope


},


headers={"Content-Type": "application/x-www-form-urlencoded"}


)


return resp.json()["access_token"]





Token Handling

Access Token Validation




// JWT verification middleware


const jwt = require("jsonwebtoken");


const jwksClient = require("jwks-rsa");




const client = jwksClient({


jwksUri: "https://auth.example.com/.well-known/jwks.json"


});




function verifyToken(req, res, next) {


const authHeader = req.headers.authorization;


if (!authHeader?.startsWith("Bearer ")) {


return res.status(401).json({ error: "Missing token" });


}




const token = authHeader.split(" ")[1];




jwt.verify(token, (header, callback) => {


client.getSigningKey(header.kid, (err, key) => {


callback(err, key.getPublicKey());


});


}, {


algorithms: ["RS256"],


issuer: "https://auth.example.com",


audience: "https://api.example.com"


}, (err, decoded) => {


if (err) return res.status(401).json({ error: "Invalid token" });


req.user = decoded;


next();


});


}





Refresh Token Rotation




def rotate_refresh_token(old_token):


# Verify the old refresh token


token_data = verify_refresh_token(old_token)




# Revoke the old token


revoke_token(old_token)




# Issue new tokens


new_access = create_access_token(token_data["user_id"])


new_refresh = create_refresh_token(token_data["user_id"])




return {


"access_token": new_access,


"refresh_token": new_refresh,


"expires_in": 3600


}





Best Practices




oauth2_best_practices:


- Always use PKCE for public clients


- Use short-lived access tokens (15-60 minutes)


- Implement refresh token rotation


- Use RS256 or ES256 for JWT signing


- Validate all claims (iss, aud, exp, nbf)


- Store tokens securely (httpOnly cookies, secure storage)


- Implement token revocation


- Log all token issuance and usage





Conclusion

OAuth2 is complex but essential for modern authentication. PKCE makes authorization code flow safe for single-page apps. Use short-lived access tokens with refresh token rotation. Always validate tokens thoroughly on the server side. Keep your JWKS endpoint secure and rotate signing keys regularly.