Skip to main content

Command Palette

Search for a command to run...

JWT and OAuth explained

Updated
4 min read
JWT and OAuth explained
T

Just a guy who loves to write code and watch anime.

JWT

JSON Web Tokens (JWT) are a way to securely send information between different parts of a system. Think of it like a sealed envelope that anyone can verify came from the right place.

A JWT has three parts, separated by dots:

  • Header (what kind of token it is)

  • Payload (the actual information)

  • Signature (proves it's authentic)

It looks like this: xxxxx.yyyyy.zzzzz.

JWTs are self-contained. This means they carry all the information needed. If you have a user ID 123 and role "admin", the JWT includes this information. The server doesn't need to check a database to know who you are.

But there's a catch. The information in a JWT is only encoded (base64), not encrypted. Base64 is like writing a message using a simple code that anyone can decode. Never put sensitive data like passwords in a JWT!

Encrypted would mean both sender and receiver know the secret key. No one else can read it. Only them.

Here's what you might put in a JWT:

  • User ID

  • User role (admin, regular user)

  • When the token expires

  • What permissions the user has

Here's what you should never put in a JWT:

  • Passwords

  • Secret keys

  • Personal information

  • Credit card details

The signature part is important. It's created using a secret key that only the server knows. The server is the one who creates the JWT. This way, even though anyone can read the JWT, nobody can fake one without the secret key.

If you send a JWT pretending to be someone else with e.g. admin permissions, the server will see that the signature is invalid and reject the request. Only the server knows the secret key. JWTs are created when a user logs in. Server sends the JWT to the client.

Three common questions

What are the pros/cons of JWT?

Pros:

  • Stateless: No DB lookup needed to validate.

  • Portable: Can be used across different services.

  • Self-contained: Contains all needed info.

Cons:

  • Can get large if you store too much.

  • Can't easily revoke until expiration.

  • Need to be careful what you store (it's base64).

Where would you store a JWT in frontend?

  • HttpOnly cookie: ✅ Best for security, protects against XSS

  • Local storage: Convenient but vulnerable to XSS! Don't do this. XSS is when someone can inject code into your site.

  • Memory: ✅ Good for SPAs, lost on refresh

What happens if JWT is stolen?

  • Short-lived tokens: 15-30 minutes max

  • Proper storage: HttpOnly cookies

  • Refresh token pattern: Don't keep JWT alive forever.

    • We'll dive into this next with OAuth.

OAuth

// Basic OAuth Flow
async function basicOAuthFlow() {
  // 1. User clicks "Login with Google"
  const authUrl = `https://google.com/auth
    ?client_id=${CLIENT_ID}
    &redirect_uri=${REDIRECT_URI}
    &scope=email profile`;

  // 2. User grants permission, Google redirects back
  interface AuthResponse {
    code: string; // Temporary code
  }

  // 3. Backend exchanges code for tokens
  const tokens = await exchangeCodeForTokens(code);
  interface Tokens {
    access_token: string; // Short-lived (1 hour)
    refresh_token: string; // Long-lived (days/weeks)
  }
}

Now you would use both the access token and refresh token to make requests to protected resources.

// The Flow
class AuthFlow {
  async handleUserActions() {
    // 1. User logs in, gets both tokens
    const tokens = await login();

    // 2. Use access token for APIs
    const userData = await fetchUserData(tokens.accessToken);
    // ... access token expires after 1 hour ...

    // 3. Use refresh token to get new access token
    // Needed if access token expires. It's short-lived while refresh token is long-lived.
    const newTokens = await refreshAccessToken(tokens.refreshToken);

    // Info: Every time a new access token is requested, a new refresh token is generated.
    // The old refresh tokens are also stored and invalidated.
    // This means if someone tries to use a stolen refresh token, it won't work.
    // Not just won't it work, but all derived refresh tokens will be invalidated.
    // By that, I mean every refresh token that was generated from the old refresh token will be invalidated (kept track of via "family" field on the refresh token).

    // 4. If refresh token expires (after weeks)
    // User needs to log in again
  }
}

Purpose of access token:

  • Actual API access

  • Short-lived (1 hour typically)

  • Stored in memory or secure cookie

Purpose of refresh token:

  • Get new access tokens

  • Long-lived (days or weeks)

  • Stored in server database or secure cookie

This is to balance both good user experience and security:

  • One token living forever would be bad for security. If exposed, it could be used indefinitely.

  • Needing to log in every day multiple times would be an annoying user experience.

Three common questions

"Why not just use one long-lived access token?" -> Answered this already.

"How would you handle refresh token rotation?" -> Answered this already. Via each refresh token creation.

"What happens if access token is stolen?" -> Expires quickly on its own. Plus you can't get new tokens without refresh token.

E
erdenee1y ago

what happens if refresh token is stolen?

R
RAJAT1y ago

If refresh token is stolen then the malicious user can access the real user's session (untill it is expired) and may generate a new token. Hackers may use techniques like session hijacking, XSS, or CSRF(cross-site request forgery) to get the token.

http-only cookies allow us to store sensitive data such as refresh tokens, in a way that cannot be accessed by JavaScript. This means that even if there are vulnerabilities in your code or third-party libraries, a hacker won't be able to retrieve the refresh token.

F

I'm reading, you wait please

JWT and OAuth explained