Authentication in Microservices

If you want to learn how to handle authentication in microservices, this guide is a great place to start. We cover the three building blocks that matter and how to combine them into secure, scalable authentication for your microservices.

The three building blocks: a central identity service issues signed tokens, the API gateway verifies at the edge, and the Orders, Billing, and Notifications services verify locally

Why microservices change authentication

In a monolith, authentication is close to a solved problem. One process handles the login, keeps a session, and every request handler asks the same session store who the user is. The question and its answer live in the same deployable.

Split that monolith into services and the question "who is making this request" must be answered across process boundaries, in every service, on every hop. The obvious answers are traps. Sharing one session database couples every service to it and puts a database lookup on every internal call. Giving each service its own login multiplies user stores, password handling, and breach surface. And a request arriving at Billing may come from the internet or from the Orders service, so "who is the user" and "which service is calling" become two separate questions that both need answers.

The way out is to make identity portable: authenticate once, then carry proof of identity with each request in a form any service can check on its own. The rest of this guide is about how to arrange that.

The three building blocks of authentication in microservices

The literature calls these "patterns", and that word quietly suggests you pick one. You do not. They are three components you combine: a central identity service that owns users and issues signed tokens, verification at the API gateway, and verification inside each service. The identity service is the foundation; the other two blocks assume it exists. They are simply two places to check its tokens, and you can run either or both: with a central identity service in place, your services can verify JSON Web Tokens (JWTs) directly, no gateway required.

The table compares the blocks one at a time so each one's trade-offs stay visible; remember they combine:

1. Central identity service 2. Verify at the API gateway 3. Verify in every service
Where identity lives In one service that owns users, credentials, and orgs Verified at the edge; forwarded as headers or a token Inside the token itself, carried on every request
What each service trusts The identity service's tokens and user API The gateway, and the network behind it The issuer's signature, checked locally
Failure modes Identity service down means no new logins; extra network hop if services call it live Gateway is a single point of failure; anything inside the perimeter is implicitly trusted Revocation lags until expiry; key rotation or clock skew breaks n services at once
Operational cost One service to run well (or buy), thin verification everywhere else Low per service, high care at the edge A JWT library, keys, and config in every service, in every language

A production-shaped system usually runs all three: tokens and user records come from one identity service (block 1), the gateway rejects bad tokens at the edge (block 2), and services re-verify or at least parse the claims (block 3). The rest of this guide takes each block apart, then covers the two topics most pattern debates skip: service-to-service authentication and where user management actually lives.

If you want the long-form treatment, Chris Richardson's five-part series on authentication and authorization in a microservice architecture (Part 2, on authentication, May 2025) is the deepest independent reference on the open web, and this guide agrees with its core move: authenticate at the edge, pass verified identity inward. Where this page differs is scope. That series goes deep on authorization models; this one stays on the identity plumbing and how the three blocks combine.

How identity flows through a microservice system

Identity in a microservice system is established once and then carried. The user authenticates against one identity service and receives a signed token. The API gateway verifies that token at the edge, then forwards the verified identity to downstream services. No service ever sees a password; most never even see the login. Figure 1 traces that path end to end.

Reference architecture: the client logs in against the identity service, sends the signed token to the API gateway, the gateway verifies it against published JWKS keys and forwards identity claims to the Orders, Billing, and Notifications services

Four hops, each with a distinct job:

  1. Login. The client authenticates once against the identity service, with a password, a passkey, a magic link, or a social login, and receives a signed token.
  2. Present. The client attaches the token to every API call as Authorization: Bearer <token>.
  3. Verify at the edge. The gateway checks the token's signature against the identity service's published public keys (a JSON Web Key Set, or JWKS, endpoint), plus expiry and audience (the aud claim naming which API the token is meant for).
  4. Propagate. The gateway forwards the request with the verified identity attached, and each service reads the claims it needs (the signed name-value facts inside the token): user id, org, role.

The design question at every hop is the same: what does this component trust? The gateway trusts the issuer's signature. The services trust either the gateway (block 2), the signature itself (block 3), or both. Making those trust decisions explicit is most of the work; the OWASP Microservices Security Cheat Sheet is a solid checklist for auditing them, and it lands on the same recommendation this page does: propagate identity in a signed structure, not a bare header.

Building block 1: The central identity service

One dedicated service owns authentication end to end: the user store, credentials, login flows, org membership, and token issuance. Every other service consumes identity instead of implementing it. This block comes first because the other two assume it when they say "the issuer": gateway or no gateway, something has to mint the tokens. It is also the block managed identity platforms productize. Figure 2 puts it at the center.

Building block 1: one identity service owns users, orgs, plan, and flags; web and mobile frontends and the backend services all consume the same user object

The core argument is about duplication. Login pages, password reset, multi-factor authentication (MFA), social providers, org invitations: implementing that once is a project, implementing it per service is a disaster that also multiplies your breach surface. Centralizing puts the sensitive material (credential hashes, reset tokens, session state) behind one hardened boundary and leaves every other service holding nothing worth stealing.

The classic objection is latency: if every request triggered a call to the identity service, you would have built a distributed monolith. Tokens dissolve the objection. The identity service is on the hot path only at login and token refresh; every ordinary request is verified locally from its signature, at the gateway, in the service, or both. The blocks are halves of one design: central issuance, distributed verification.

In protocol terms, this block is usually an OAuth 2.0 and OpenID Connect (OIDC) server. OAuth 2.0 defines how tokens are requested and issued, OIDC standardizes the identity layer on top, and the machinery this page leans on, bearer tokens, JWKS discovery, token exchange, all comes from that standards family. Building on the standard is what keeps the parts interchangeable: Keycloak, the managed platforms, and your gateway's JWT filter all speak the same protocol.

You can self-host this block with Keycloak or an in-house service, or consume it as a managed platform; the product section at the end maps the blocks to that option.

What remains yours either way: authorization. The identity service says who the user is and which org they belong to. Whether this user may cancel that subscription is domain logic, and it belongs in the service that owns the domain.

Building block 2: Verify at the API gateway

In the gateway arrangement, one component at the edge verifies every incoming token, rejects the bad ones, and forwards the good requests with identity attached. Services behind it carry no token logic at all. You get one checkpoint to harden, and one component whose compromise or misconfiguration exposes everything behind it. Figure 3 shows the shape.

Building block 2: the client sends a bearer token to the API gateway, the gateway verifies the JWT once, and the Orders, Billing, and Notifications services trust the identity headers it forwards

Every major gateway can do this verification for you. On the JVM it is Spring Cloud Gateway, shipped in both reactive (WebFlux) and servlet (MVC) variants. Envoy ships a dedicated jwt_authn filter, and the Kubernetes-native Envoy Gateway project exposes the same capability declaratively. Kong validates JWTs too, with a caveat worth knowing: its open-source jwt plugin expects each signing key registered as a consumer credential, while automatic JWKS fetching and rotation live in the enterprise OpenID Connect plugin. And the managed clouds validate with configuration rather than code: AWS API Gateway's JWT authorizers (HTTP APIs; REST APIs still need a Lambda authorizer), Azure API Management's validate-jwt policy, and Google Cloud's API Gateway and Cloud Endpoints via a jwks_uri in the API config.

Whatever runs at your edge, the validation logic has the same shape. Here it is as Express middleware, using jose:

ts
// the same three lines from the JWT guide, now as gateway middleware
import { createRemoteJWKSet, jwtVerify } from 'jose'; // pin: jose v6

const JWKS = createRemoteJWKSet(
  new URL('https://auth.example.com/.well-known/jwks.json')
);

export async function authenticate(req, res, next) {
  const token = (req.headers.authorization ?? '').replace(/^Bearer /, '');
  try {
    const { payload } = await jwtVerify(token, JWKS, {
      issuer: 'https://auth.example.com',
      audience: 'https://api.example.com',
      algorithms: ['RS256']
    });
    req.user = payload; // sub, org, role travel downstream from here
    next();
  } catch {
    res.status(401).end();
  }
}

Figure 4Gateway verification middleware with jose: issuer, audience, and algorithm are pinned explicitly, and the verified payload travels downstream as req.user.

The trade, stated once:

  • For: authentication logic lives in one place; services stay small; security policy, rate limiting, and audit logging get a single enforcement point; swapping identity providers touches one component.
  • Against: the gateway is a single point of failure and must be run highly available; everything behind it is implicitly trusted, so a compromised internal service can impersonate anyone unless you add service-to-service checks; and "the network is the perimeter" is exactly the assumption zero-trust architectures (which treat the internal network as hostile by default) exist to remove.

That last point is why the gateway block almost never stands alone in serious systems. It is the front door, not the whole security model.

So which do you pick for a brand-new system? Neither alone, and the emphasis goes to block 3: per-service verification is a library import and a cached key set, so make it the baseline. You will almost certainly run a gateway anyway, for routing, TLS termination, and rate limiting, and once it is there, letting it also reject bad tokens costs a few lines of configuration and spares your services garbage traffic. Where block 2 becomes truly valuable is at scale and in mixed estates: one place to enforce coarse policy, rate limits, and audit logging across many services, a config-level checkpoint in front of services written in many languages, and cover for legacy services that cannot verify tokens themselves. If none of that describes your system yet, a gateway that only routes while your services verify is a sound starting point.

Building block 3: Verify in every service

In the per-service arrangement, each service verifies the JWT itself: fetch the issuer's public keys once, cache them, and check every request's signature locally. No shared session store, no call home, no implicit trust in the network. The cost is that token handling becomes a distributed concern with n copies, as Figure 5 shows.

Building block 3: the auth server issues a signed JWT to the client, the client presents it on every request, and each service verifies the signature locally against cached JWKS keys

The mechanics are exactly the JWT flow: signed claims, JWKS, local verification with an algorithm allowlist. If any of that is fuzzy, read how JWT authentication works first; everything there applies per service here. Library support is mature in every ecosystem: jose on Node and edge runtimes, PyJWT in Python, Nimbus JOSE + JWT on the JVM.

What the block buys you is real. Verification is local math, so services scale independently and keep authenticating even when the identity service is briefly down. Because every service checks the signature itself, a request forged inside your network fails just like one forged outside it. And it serves clients that have no backend of their own: a pure frontend app (a single-page app or a mobile app) obtains its token straight from the identity service and calls the services with it, no intermediate backend required; the verification still happens inside each service it calls. That combination is why Richardson's 2025 series builds its authorization model on JWT-based access tokens too.

The failure modes are just as real, and they are operational rather than cryptographic:

  • Revocation lags. A valid signature stays valid until the token's built-in expiry: the exp claim, a timestamp the issuer stamps into every token, typically minutes to an hour out. Locking out a compromised account takes effect at that expiry, everywhere, unless you add a denylist.
  • Key rotation breaks in bulk. Rotate signing keys carelessly and every service rejects every token at the same moment. JWKS caching makes rotation routine, but only if all n services implement the fetch-and-cache correctly.
  • Config drifts. Each service must pin its accepted algorithms and validate issuer and audience. The service that skips the audience check is the one that accepts a token minted for a different API.
  • Clock skew bites. Distributed clocks disagree by seconds; verifiers need a small tolerance or freshly issued tokens bounce.

None of this is a reason to avoid the block. It is a reason to ship token verification as one shared, versioned library per language rather than letting each team hand-roll it.

Security considerations at the edge

Every block above assumes the client holds a token, and for the most common client, the browser, that assumption is where things go wrong. Say your web app is a single-page app that keeps the user's token in localStorage or a JavaScript variable so it can call your API. Anything your scripts can read, every other script on the page can read too: one compromised npm dependency, one injected analytics or ad script, and the token is quietly copied out. From that moment the attacker is the user. Same claims, any machine, until the token expires, and nothing in your microservices notices, because every request it makes is perfectly valid.

The fix is to take the token out of the browser entirely. That is the backend-for-frontend (BFF) pattern, and it splits the edge into three roles. The browser holds only an ordinary httpOnly session cookie, which scripts cannot read, so there is nothing left to steal. A thin backend owned by the web app holds the actual tokens, exchanges the cookie session for them, and makes the calls to internal services. The services behind it see standard bearer tokens and change nothing. Users get instant logout for free, because killing the session at the BFF kills everything.

The pattern has one honest toll: cookies revive cross-site request forgery (CSRF). Browsers attach cookies automatically, so a malicious page can trigger requests to your BFF with the user's session attached. The countermeasures are well-trodden, SameSite cookies plus a CSRF token, but they are part of the pattern's price, not optional.

Two more edge considerations worth deciding deliberately:

  • Token lifetime and refresh rotation. Short access-token lifetimes bound how long a stolen token works. Pair them with rotating refresh tokens with reuse detection: a stolen refresh token gets used twice, once by the attacker and once by the real client, and the reuse is the alarm that revokes the whole session.
  • Mobile apps. No injected-script problem, so no BFF needed for that reason, but tokens belong in the platform's secure storage (iOS Keychain, Android Keystore), never in plain files or preferences where device backups and other apps can reach them.

Service-to-service authentication: when your microservices call each other

Everything so far has dealt with requests arriving from the outside: a user's app, or an external service calling your API. Those enter through the gateway, present a token issued for them, and the three building blocks have them covered. Your own microservices calling each other is a different situation. Assume an Orders service and a Billing service, both needed for a user to cancel a subscription: the request enters through the gateway to Orders, and Orders then calls Billing internally to stop the charges. That internal hop never touches the gateway, and it carries considerations the external path does not have.

Two things are different about the internal call. First, the caller is no longer the party the token is about. On the external path, whoever presents a user's token is that user's own app; here, Orders presents a token about someone else, and a forwarded user token says nothing about who forwarded it. Second, the caller has an identity of its own worth checking: Orders may be allowed to call Billing's cancel endpoint while a third service, say Notifications, is not, and a compromised internal service is a threat in its own right. This is where the promise from the start of the article lands: "who is the user" and "which service is calling" become two separate questions with separate tools. The tools combine rather than compete, and most systems need only one or two of them. Figure 6 shows the hop and the two questions hanging over it.

The service-to-service problem: Orders calls Billing inside the network without passing the gateway, and the forwarded user token cannot say which service is calling

The baseline is to not answer the caller question at all. If the gateway is the only way in and everything behind it runs in one locked-down network, many teams accept the implicit answer: the call came from inside, so it is one of ours. That is a legitimate trade-off, not a sin. But it is exactly the assumption a compromised internal service abuses, and removing it is the whole idea behind zero trust.

Which user is this for: forward the user's token. When Orders calls Billing on behalf of a user, Billing usually needs to know which user, and the simple approach forwards the user's original JWT on the internal call. For many systems that is fine. Its weakness is scope: the downstream service receives a token that grants everything the original did, so a compromised middle service can replay it anywhere the token is accepted.

Which service is calling: give each service a token of its own. A forwarded user token cannot identify the caller, but the same mechanism can: have Orders present a second token that names the service (sub: Orders) and its target (aud: Billing), so Billing checks callers the same way it checks users. This is what most teams actually run, and the platform often mints these workload tokens for you: on Google Cloud Run, a service fetches an identity token for its target from the metadata server and IAM enforces who may call whom; on Kubernetes, pods receive short-lived, audience-bound service account tokens any verifier can check against the cluster's key set; on AWS, internal calls are typically signed with the caller's IAM role rather than carrying a JWT at all. Without a platform doing it, the OAuth client credentials grant is the same idea: your identity service issues each service its own credential, and services fetch tokens under their own identity.

Token exchange answers both questions in one token. OAuth 2.0 Token Exchange (RFC 8693) combines the two: a service presents the token it received and gets back a narrower one, scoped to the downstream audience and carrying both the user (sub) and the acting service (act claim). Billing then sees "this specific service, acting for this specific user, for this specific purpose". It costs a call to the identity service per exchange, so reserve it for the boundaries that matter: payments, admin surfaces, anything crossing a trust zone. Figure 7 lines the three token answers up against the two questions.

Three ways Orders can call Billing: forwarding the user's JWT answers only which user; adding a workload token also answers which service is calling; token exchange folds user, caller, and audience into one scoped token

Mutual TLS (mTLS) is for when the network itself is the boundary you distrust. Everything above authenticates requests; mTLS authenticates connections. Both sides present certificates, so Orders proves it is Orders before a single application byte flows, and the traffic is encrypted on the wire. Issuing and rotating workload certificates by hand is miserable, which is why in practice mTLS arrives via a service mesh (Istio or Linkerd), infrastructure that runs alongside your services and handles the certificates automatically, with no application changes. It becomes relevant when workload tokens are not enough: multiple teams deploying into one shared cluster, compliance asking how services authenticate to each other, or a zero-trust mandate that no connection goes unauthenticated. If none of those apply, plenty of production systems run well on workload tokens and never adopt a mesh. Figure 8 shows where mTLS sits: beneath the requests, on the connection itself.

mTLS via a service mesh: the mesh issues short-lived certificates to Orders and Billing, and mutual TLS verifies both ends of the connection and encrypts the traffic before any request flows

A sane maturity path: start with forwarded user JWTs and network controls, add per-service workload tokens when "which service is calling" starts to matter (often free, since your platform already mints them), introduce RFC 8693 exchanges at the sensitive boundaries, and reach for mesh-issued mTLS when the network itself stops being trustworthy. All of it assumes a working identity service behind it, which is one more argument for block 1.

What AI callers change

Until recently, an API had two kinds of callers: people, through the web and mobile apps you built for them, and other servers, through integrations someone approved one by one. A third kind is arriving fast, and this time it is a product opportunity rather than an integration chore: your users' AI agents. If your product is useful, your users will want their agents to use it, and products increasingly treat "AI can call us" as a feature to ship rather than traffic to block. What is genuinely new is the shape those callers take. Traditional machine-to-machine traffic was direct API calls from another backend; an AI caller might drive your CLI and wrap dozens of calls into one task, or arrive through a Model Context Protocol (MCP) server that exposes your API as tools. Figure 9 puts the new arrivals next to the callers you already planned for.

New callers, same trust model: web users, server integrations, and now AI agents arriving through CLIs and MCP servers, all verified by the API with the same scoped, revocable tokens

None of this changes the trust model above. An agent is a machine caller, usually with a user behind it, which is exactly the case the service-to-service section covered: it should hold a scoped, short-lived, revocable credential rather than the user's full token, and "acting for whom" belongs inside the token (the act claim from token exchange), not in a prompt. An autonomous agent with no user behind it is the plain machine-to-machine case. Either way, your API verifies it like every other caller: signature, audience, scope, expiry.

What changes is who shows up, and whether the service was built expecting them. A service that only ever anticipated its own UI in front of it, or a handful of hand-approved server integrations, will now meet machine callers at user-like volume doing user-like things, and "making your tools secure for AI" mostly means finishing the homework this page already assigned. Expect more machine identities than human ones, because every agent, automation, and model-tool integration is another caller to authenticate. User-issued API tokens with narrow scopes stop being a developer afterthought and become a product surface, since users will want their agents running on credentials they control, scoped to what the agent needs and nothing more. And instant revocation matters more than ever: a misbehaving agent replays a credential far faster than any human attacker, so a revocation story that waits for token expiry is a weaker position than it was.

User management across microservices: orgs, tenants, and identity propagation

Every block so far has moved identity as claims: who the user is, which org they belong to, what role they hold, carried on each request. But services need more than identity. Billing prints a name and an email address on invoices. Notifications keeps device tokens and delivery preferences. Support tooling searches users by name. None of that fits in a token, so sooner or later every team asks the same innocent question: should we just keep our own users table?

Say two teams answer yes. Within a month the copies disagree, and the bugs do not look like auth bugs. They surface as support tickets: a user renames their account and invoices keep the old name. An employee is deactivated and keeps receiving notifications. A deletion request arrives and nobody can say with confidence how many databases hold this person. Duplicated user data is how distributed systems rot, and it rots quietly, because every individual service still works.

The discipline that prevents it is ownership. Exactly one service, the identity service from block 1, owns the user record. Every other service stores the user id as a foreign key and asks for, or is told, the rest. Where a service genuinely needs user data hot, it keeps a read-only projection it never edits, and treats the user id as the only durable reference. The same ownership applies to organizations and tenant membership: the identity service knows which users belong to which org and what role they hold there, and downstream services enforce their own domain rules with that context.

So how does that context reach the services on every request without a database lookup? As claims. Concretely, identity propagation means every internal request carries a claims payload shaped like the one in Figure 10, signed by the issuer rather than assembled by hand:

json
{
  "iss": "https://auth.example.com",
  "sub": "usr_4f7Qk2M9pTzX",
  "aud": "https://billing.internal",
  "org": "org_8kPw2Rv6",
  "role": "admin",
  "plan": "pro",
  "exp": 1785229200
}

Figure 10The signed claims payload an internal request carries. The aud pins this token to Billing specifically, and org, role, and plan are the claims downstream services enforce their own rules with.

The honest shortcoming of claims is that they are a snapshot. A token minted at 09:00 still says role: admin at 09:30, after you revoked the role. Short token lifetimes bound how stale a claim can get, and for changes that cannot wait, push beats poll: the identity service emits an event when a user, org, or membership changes, and services holding projections react to it, rather than re-syncing whole profiles and quietly rebuilding the duplicated tables the ownership rule exists to prevent.

For B2B products the org and tenancy side of this deserves its own treatment; the tenancy models and their trade-offs live in our identity and auth toolbox, on the same user model as authentication.

The signature is the point. A bare X-User-Id header set by the gateway works until the day some internal path lets a caller set it themselves; a signed structure fails closed. This is the OWASP cheat sheet's recommendation, and it is worth adopting from day one.

One error from an older generation of articles needs killing explicitly, because this page replaces one that made it: passwords are not "encrypted", and no amount of "256-bit end-to-end encryption" makes password storage secure. Encryption is reversible by design; anyone with the key recovers every password. Passwords must be hashed with a slow, salted, purpose-built algorithm: argon2id by current guidance, bcrypt as the battle-tested elder. Exactly one service, the identity service, should ever touch a password or its hash. If any other service in your system can see a password, the architecture is wrong before the algorithm discussion even starts.

When is the three-component architecture overkill?

If your product is one deployable application, the full three-block architecture is overkill: it takes real time to stand up and charges upkeep forever after. Distributed identity is the price of a distributed system; do not pay it before you have one. Pragmatism wins.

Be equally pragmatic about the simplest alternative, though, because session-based auth outgrows its clothes faster than teams expect. Part of it is mechanical: every session check is a lookup against shared state, fine at small scale, an increasingly poor trade in any application handling serious call volume. But product reality usually arrives first. Your users expect to sign in with Google or with passkeys, your enterprise customers expect to connect their own identity platform, and your callers stop being only humans in a browser, because servers and AI agents need credentials a session cookie cannot represent. None of that is microservices pressure; it is authentication pressure, and it hits monoliths too. Microservices authentication is one piece of a bigger authentication story, and the pieces share a foundation.

The coffee-test version: would I tell another engineer with a two-person team and one backend to stand up a gateway, a JWKS pipeline, and a mesh? No. Would I tell them to hand-build session auth and grow it login method by login method? Also no. I would tell them to keep authentication in one module, take it from a library or platform that already speaks tokens and multiple login methods, and spend the week on their product.

What is worth doing from day one is building on the principles while the architecture is still a monolith, because principles are cheap now and migrations are not. Keep authentication in one module, with the rest of the app forbidden from touching credentials. Reference users by id everywhere, never by copied profile. If a mobile app or a public API is plausible in your future, let the monolith issue JWTs for its own API; sessions for the browser and tokens for machines coexist happily. None of this takes meaningfully longer when a library or platform does the heavy lifting, and it makes the eventual split boring, because the expensive part of adopting these blocks late is never the infrastructure. It is untangling user data that leaked into every service's database.

Reach for the blocks when the forcing functions arrive, and they are concrete: a second backend service that must know who the user is, a mobile app or third-party API where cookies stop making sense, or a second frontend against the same accounts. Even then, adopt incrementally. Central identity service first, since untangling user tables later is the expensive part. Gateway verification second. Per-service validation, workload tokens, token exchange, and mTLS when the blast radius justifies them.

The summary of the whole page: identity is issued in one place and verified at every boundary you are not willing to trust blindly. How many boundaries that is depends on your system; maybe only the gateway, maybe every service, eventually every network hop with mTLS. Start with the identity service, because everything else assumes it. Add verification layers as your trust assumptions tighten. And keep passwords in exactly one place, hashed, behind a boundary you defend.

The Bridge: one platform,
ready for you

One platform that handles it all, so you do not have to build any of this. Two minutes to integrate, and you are back to your core innovation.

The foundation

Central identity platform

One platform for login, signup, users, orgs, and token issuance: multi-tenant from day one, built for B2C and B2B, with every sign-in method your users expect. One token across all your integrations.

Ready for your microservices

Your gateway and every service verify tokens locally: no extra network hop, no vendor on your request path. Drops into the architecture exactly as this guide draws it.

Users, APIs, MCP & CLI

One issuer for every caller: people signing in, external API callers, and AI agents arriving through CLIs and MCP servers.

Access control

RBAC & privileges

Roles and privileges defined once, arriving in every signed JWT as claims: tenant, role, privileges, plan.

API tokens as a product

Your users mint their own scoped tokens from a drop-in UI. Stored hash-only, shown once, revocable anytime.

Instant blocking

Revoke a credential and introspection kills it now, not at expiry. The gap most JWT setups leave open.

Operate & grow

Change events, pushed

Signed webhooks when a user, tenant, membership, subscription, or entitlement changes. Trigger a refresh; claims are fresh now.

Usage limits built in

Plans, quotas, entitlements, and feature flags on the same user object the token describes.

SDKs & drop-in UIs

Ready for any stack: Next, React, Svelte, Angular, and more. Two minutes to integrate into your app.

Common questions

Should every microservice validate the JWT?
Every service reachable from outside your trust boundary should. For deep internal services the honest answer is a trade-off: re-verifying everywhere is defense in depth and costs little with cached JWKS keys, while trusting gateway-forwarded identity is simpler but makes the network perimeter part of your security model. Pick deliberately, not by default.
Do I need an API gateway to secure my microservices?
Not for verification alone. Per-service JWT validation is a library import and a cached key set, and it is the baseline. You will likely run a gateway anyway for routing, TLS, and rate limiting, and letting it also reject bad tokens costs a few lines of configuration. The gateway earns its keep at scale: one policy and audit point across many services and languages, and cover for legacy services that cannot verify tokens themselves.
Where do sessions fit in a microservice architecture?
At the edge. A browser-facing app or BFF (backend-for-frontend) can keep a classic httpOnly session cookie with the user, then exchange it for a token when calling internal services. Users get instant logout and no token storage in the browser; services still get stateless verification. Sessions and tokens are layers, not rivals.
How do services authenticate to each other?
Two different questions hide in there. Which service is calling: give each service a token of its own, platform-minted on Cloud Run or Kubernetes, IAM-signed on AWS, or client credentials from your identity service, with mTLS via a service mesh when connections themselves must be authenticated. Which user is this call for: propagate the user's token or exchange it for a narrower one using OAuth 2.0 Token Exchange (RFC 8693). Most systems need both answers.
Do I need mTLS between microservices?
Not to start, and often never. The question mTLS answers, which service is calling, is usually answered with workload tokens first: platform-minted identity tokens on Cloud Run or Kubernetes, IAM-signed calls on AWS, or client credentials from your own identity service. Adopt mTLS when tokens are not enough: multiple teams in one cluster, compliance requirements, or a zero-trust mandate that no connection goes unauthenticated. In practice it arrives via a service mesh like Istio or Linkerd, as infrastructure rather than application code.
How should AI agents authenticate to my API?
As machine callers acting for a user. Give the agent a scoped, short-lived, revocable credential rather than the user's full token, and put acting-for-whom inside the token (the act claim from token exchange), never in a prompt. An autonomous agent with no user behind it is a plain machine-to-machine caller. Whether it arrives through your CLI or an MCP server, your API verifies it like every other caller: signature, audience, scope, expiry.
Should each microservice have its own auth, or one shared service?
One identity service. Per-service auth means multiple user stores, multiple password-hashing implementations, and login flows that drift apart, and every one is a separate breach surface. Services stay authoritative for their own domain data but consume identity from one place, storing only the user id as a foreign key.
Ready to

start using The Bridge?

Auth, billing, and feature flags on one user object. Getting started takes two minutes.

Sign up and start building
Keep building

Explore every identity guide

Every auth question you were saving for later, answered in its own guide. Pick one and go build.