OAuth 2.0 and JWT: Authentication and Authorisation Explained
Authentication and authorisation are among the most critical and most commonly misimplemented aspects of web development. OAuth 2.0 and JSON Web Tokens (JWT) are the industry-standard solutions — but they're often implemented incorrectly, leading to security vulnerabilities. This guide explains how they work and how to use them correctly.
Authentication vs Authorisation
These terms are frequently confused. Authentication answers "Who are you?" — verifying identity, typically via password, biometrics, or a federated identity provider. Authorisation answers "What are you allowed to do?" — checking permissions after identity is established. A 401 HTTP status means authentication failed; 403 means authorisation failed.
What is OAuth 2.0?
OAuth 2.0 is an authorisation framework — a standard for letting users grant third-party applications access to their resources without sharing their passwords. When you click "Sign in with Google" or "Connect with GitHub", OAuth 2.0 is running behind the scenes. The user grants specific permissions (scopes) to an application without revealing their credentials to it.
OAuth 2.0 Flows
Authorization Code Flow (with PKCE for SPAs and mobile apps) is the recommended flow for most applications. The user is redirected to the authorization server, authenticates, approves scopes, and is redirected back with an authorization code. The app exchanges the code for tokens. PKCE prevents code interception attacks.
Client Credentials Flow is for machine-to-machine authentication — no user involved. A service uses its client ID and secret to get an access token directly. Common for API-to-API calls.
Device Authorization Flow is for devices without browsers (smart TVs, CLI tools) — shows a code for the user to enter on another device.
Implicit Flow and Resource Owner Password Credentials are deprecated — don't use them in new implementations.
JWT Structure Explained
A JSON Web Token has three Base64url-encoded parts separated by dots: header.payload.signature. Use our Base64 tool to decode each part.
- Header: the algorithm used (
{"alg":"RS256","typ":"JWT"}) - Payload (claims): the token's data —
sub(subject/user ID),iss(issuer),aud(audience),exp(expiry Unix timestamp),iat(issued at), plus custom claims - Signature: a cryptographic signature over the header and payload, verifiable with the issuer's public key
exp claim. Never paste production tokens into third-party sites.Access Tokens vs Refresh Tokens
Access tokens are short-lived (15 minutes to 1 hour) credentials used to authenticate API requests. Because they're short-lived, a stolen access token has limited damage potential. Refresh tokens are long-lived (days to weeks) and stored securely — used only to obtain new access tokens when the current one expires. Never send refresh tokens to APIs. Rotate them on use (one-time use refresh tokens).
Token Storage: Where and How
In web apps: store access tokens in memory (JavaScript variables). Store refresh tokens in HttpOnly cookies (inaccessible to JavaScript, protected from XSS). Never store tokens in localStorage — they're accessible to any JavaScript on the page, including injected scripts. In mobile apps, use the platform's secure keychain (iOS Keychain, Android Keystore).
Scopes: Fine-Grained Permissions
Scopes define the specific permissions a token grants. Request only the scopes you need (principle of least privilege). Common scope patterns: read:users, write:posts, admin:org. When displaying the OAuth consent screen, the scopes you request should match exactly what you need — requesting broad scopes erodes user trust.
Common JWT Security Mistakes
Accepting "none" algorithm: early JWT libraries accepted {"alg":"none"} as valid, allowing tokens without signatures. Always specify the expected algorithm explicitly in your verification code. Not validating claims: always verify iss, aud, and exp — an expired token or one issued by a different service should be rejected. Symmetric secrets that are too short: HS256 secrets should be at least 256 bits of entropy. Use our Password Generator to generate cryptographically strong signing secrets.