← Back to list

💡 “I Already Have a Token — Why Do I Need Another One?”

(And how this idea quietly powers patterns like MCP Server Auth)

Apoorva Dixit in JavaScript in Plain English · 2025-11-19 19:10 · 50 claps · 3.2 min read
#oauth2 #token-exchange #security #mcp-server
Open on Medium ↗
Wiki topics: AGT · AI Agents 🔧 · Data Engineering

Token Exchange (RFC 8693)

Token Exchange (RFC 8693)

💡 “I Already Have a Token Why Do I Need Another One?”

(And how this idea quietly powers patterns like MCP Server Auth)

Understanding Token Exchange (RFC 8693) Through a Simple Service A → Service B Story

In OAuth conversations, we’ve all heard about the authorization code exchange the classic login flow where a user signs in, your app receives an authorization code, and the backend exchanges it for tokens.

But then you stumble upon something newer sounding: Token Exchange.

And the immediate reaction is usually:

“Wait… if I already have an access token, why would I ever need another one?”

This guide explains that in the simplest possible way one user, two services, one diagram and a quick nod to how this same principle shows up in MCP Server Auth patterns.

🧩 The Setup: One User, Two Services

Let’s consider:

  • Service A the application the user interacts with
  • Service B a backend service that performs a sensitive action
  • Authorization Server issues and validates tokens
  • User who logs in through the normal authorization code flow

When the user logs into Service A, the application receives an access token:

audience: Service A
scope: profile.read

Great Service A can now read the user’s profile.

But what happens when Service A needs to call Service B to perform something more sensitive like:

scope: payment.write

That’s where Token Exchange comes in.

📊 Sequence Diagram

Token Exchange in Action (RFC 8693)

Token Exchange in Action (RFC 8693)

🔄 Token Exchange in Action (RFC 8693)

OAuth 2.0 Token Exchange, defined in RFC 8693 → https://www.rfc-editor.org/rfc/rfc8693, lets you trade one token for another often with:

  • different scopes
  • different audiences
  • different delegation semantics

Service A sends a request like this:

grant_type=urn:ietf:params:oauth:grant-type:token-exchange
subject_token=<access_token_for_ServiceA>
subject_token_type=access_token
requested_token_type=access_token
audience=ServiceB
scope=payment.write

Here’s what’s happening:

subject_token → the original access token issued to Service A

audience=ServiceB → the new token must be valid for Service B

scope=payment.write → Service A needs higher privilege

The Authorization Server then:

1. Validates the subject_token

Checks:

  • signature & expiry
  • token was issued to Service A
  • token hasn’t been revoked

2. Validates requested scope & audience

Makes sure:

  • Service A is allowed to request payment.write
  • audience matches Service B

3. Optionally checks the user

Only if the system needs to enforce:

  • user permissions
  • user consent
  • policy & compliance rules

If everything is valid, the Authorization Server returns:

new access_token
scope: payment.write
audience: ServiceB

Now Service A can call Service B safely “on behalf of the user.”

🚫 Why You Can’t Reuse the Access Token Issued to Service A

This is the big question and probably the reason you’re reading this:

“If a user is already authenticated, why can’t I just use the same token to call Service B?”

Four important reasons.

1. Wrong Audience

The first token was issued for Service A.

Service B should reject it otherwise a token meant for one system would magically work everywhere. That is a massive security flaw.

2. Wrong Scope

The original token probably has:

scope: profile.read

But Service B requires:

scope: payment.write

These scopes describe different privileges. Reusing the original token breaks the least privilege principle.

3. Different Security Boundaries

Service A and Service B represent different trust zones.

You need a token that was explicitly minted for Service B’s environment, policies, and audit requirements.

4. Proper Delegation

Tokens issued via Token Exchange can embed:

  • who the user is (sub)
  • which service is performing the action (act)
  • what the user is allowed to do
  • what the service is allowed to do

This gives rich audit trails:

“User X initiated the payment, but the call was made by Service A using a token explicitly issued for Service B.”

🧠 The Cleanest Way to Think About It

Authorization Code Exchange

Used during login. Input: authorization code. Output: tokens for Service A.

Token Exchange

Used during backend delegation. Input: existing access token. Output: a new access token for Service B.

One is for user authentication. One is for service-to-service authorization.

⚡ A Quick Nod to MCP Server Auth

If you’ve looked at MCP servers lately, you might notice a similar philosophy:

Capabilities and tokens in MCP are scoped to the specific tool, resource, or action and you can’t reuse a capability across unrelated boundaries.

Just like Token Exchange prevents one token from being reused across services, MCP prevents a capability from leaking across tools.

Similar principle, different implementation.

🪄 In One Sentence

The access token from login was never meant for Service B Token Exchange (RFC 8693) gives us a clean, safe, standardized way to obtain the right token for the right service with the right scopes.


메타데이터
post_id
84d0a461e28b
slug
i-already-have-a-token-why-do-i-need-another-one-84d0a461e28b
url
https://javascript.plainenglish.io/i-already-have-a-token-why-do-i-need-another-one-84d0a461e28b
canonical_url
https://javascript.plainenglish.io/i-already-have-a-token-why-do-i-need-another-one-84d0a461e28b
author_url
https://medium.com/@apoorva.gcet
status
ok
fetched_at
2026-08-01 13:20:37