I've seen OAuth2 and JWT used everywhere, but there's a big difference between using them and doing them right. The details matter, like how you design your tokens, which grant types you choose, and how carefully you validate them. Get these wrong and you'll have something that looks secure but isn't.

OAuth2 provides multiple grant types for different client contexts. For browser-based and mobile clients, Authorization Code with PKCE is the correct grant, since there's no client secret on the frontend. Client Credentials are for service-to-service authentication where no user is involved. I'd avoid Implicit flow and Resource Owner Password Credentials, as they provide no security over sending passwords directly.

I've seen cases where Implicit flow is still used, and it's a bad idea. It's like sending passwords directly to the client, which defeats the purpose of authentication. For example, a popular e-commerce site was using Implicit flow, and it was vulnerable to CSRF attacks. We had to rewrite the authentication flow to use Authorization Code with PKCE, which made it much more secure.

A JWT contains a header, payload, and signature. When designing the payload, use 'sub' for the user identifier, not email, which can change. Include 'aud' to prevent token reuse across services, set a short 'exp' to limit the window of compromised token validity, and only include the claims the resource server needs. Over-claiming creates large tokens and inflexible authorisation.

Token design decisions have a significant impact on security. Using 'sub' for the user identifier and including 'aud' to prevent token reuse are crucial. The 'exp' claim should be set to a short duration, and only the necessary claims should be included in the token. Over-claiming can lead to large tokens and inflexible authorisation, making it harder to manage access control. For instance, we had a situation where a token was 10KB in size, and it was causing performance issues. We had to reduce the number of claims in the token, which improved performance and reduced the attack surface.

JWT validation must verify the signature, expiry, audience, and issuer. Missing any of these validations creates an exploitable security vulnerability. The signature must be verified using the correct algorithm, and 'none' algorithm should be rejected regardless of what the token header says. The OWASP JWT Security Cheat Sheet provides a complete validation checklist. It's essential to use a library that implements JWT validation correctly, such as the one provided by the Java JWT library.

Access tokens should be short-lived, lasting minutes to an hour. Refresh tokens allow obtaining new access tokens without re-authentication. But refresh token rotation is crucial: issue a new refresh token with each use, and invalidate the old one. This limits the impact of refresh token theft, as a stolen refresh token can only be used once before the legitimate holder's next use detects the compromise.

The grant type selection determines the security properties of the authentication. Authorization Code with PKCE is the correct grant for browser-based and mobile clients, while Client Credentials are for service-to-service authentication. Understanding the different grant types and their use cases is essential for building secure APIs.

I've seen cases where refresh tokens are not rotated, and it's a security risk. Rotate refresh tokens and detect single-use violations to prevent unauthorized access. It's not just about following best practices, but also about understanding the security properties of the authentication.

By following these best practices and understanding the details of OAuth2 and JWT, you can build secure APIs that protect user data and prevent unauthorized access. It's not just about using the right technologies, but also about doing them right.