How to accept Claude as a trusted issuer on your MCP server

Claude now auto-connects plugins at login when an MCP server trusts it as an issuer. The full implementation: JWT bearer grant, CIMD, nine checks, working code.

Nov 3, 202614 min read

On November 3, 2026, Anthropic announced that Claude can connect plugins for people the moment they log in, with no sign-in page and no consent screen, when the plugin's MCP server accepts Claude as a trusted issuer. This guide shows what your server has to do to support that, with working code.

We built this into Server4Agent's authorization server, and wrote this while doing it. Claude's documentation tells you what to check. This adds the order things go wrong in, the code, and the traps that are not on any checklist, including one place where the general MCP guidance points the opposite way.

On this page: Quick answer · What it means · EMA, ID-JAG and XAA · Claude-issued or IdP-issued · The five steps · Full code · Mistakes to avoid · Testing · Troubleshooting · FAQ

Quick answer

To accept Claude as a trusted issuer, your MCP server's authorization server has to do four things:

  • Advertise and accept the JWT bearer grant (urn:ietf:params:oauth:grant-type:jwt-bearer, RFC 7523) at its token endpoint.
  • Recognize Claude as a client without Dynamic Client Registration, which in practice means supporting Client ID Metadata Documents. DCR does not work with this flow.
  • Let each customer's admin register one trusted issuer for their workspace, in your product's own settings.
  • Validate every assertion in a fixed order, including an exact issuer match and a replay check, then find the user by a verified email address inside that one workspace.

Your MCP server itself barely changes. It still answers an unauthenticated call with a 401, and still receives an ordinary bearer token.

Key takeaways

  • Availability: Claude-issued auth is in beta on Claude's Team and Enterprise plans as of November 2026. The identity provider version is generally available.
  • The issuer URL has the form https://identity.anthropic.com/issuers/<issuer-id>, and each Claude organization has its own. Match it as an exact string.
  • DCR is out. A registered client's generated id can never match the client_id in an assertion.
  • Ignore grant types you do not issue. Claude's client document lists the JWT bearer grant, and resolvers that refuse unknown entries reject the whole document with errors like Invalid client_id.
  • Find people by email, not sub, for Claude-issued assertions. This is the reverse of the general advice for identity assertions.
  • Assertions are short-lived: each expires within a minute and can be used once. Allow at most 60 seconds of clock skew.
  • No refresh token. Claude asks for a new assertion each time your access token expires, so a one-hour token costs the user nothing.
  • Your token endpoint has 10 seconds to answer, and must not redirect.

What does accepting Claude as a trusted issuer mean?

A trusted issuer is the one signer a customer workspace has told your authorization server to believe. Accepting Claude as one means that when Claude presents a signed JWT saying "this is a current member of this Claude organization, at this email address", and that workspace has registered that exact issuer, your server hands back an access token without showing anyone a consent screen.

The person experiences this as the plugin simply working. An admin sets it up once, on both sides, and members of the organization never see a Connect card. Anthropic calls the user-facing feature auto-connect.

EMA, ID-JAG, XAA and auto-connect: what each name means

These terms get used interchangeably, and they are not the same thing. Each names a different layer.

NameWhat it isWho defines it
Enterprise-Managed Authorization (EMA)The MCP extension, io.modelcontextprotocol/enterprise-managed-authorization. Its stable specification is dated 2026-07-28MCP maintainers
ID-JAG (Identity Assertion JWT Authorization Grant)The signed token itself, with the type header oauth-id-jag+jwtAn IETF OAuth working group draft, not yet an RFC
JWT bearer grantHow the token is redeemed at your token endpointRFC 7523
Cross App Access (XAA)The general pattern of an identity provider brokering app-to-app access, and the name Okta's product usesOkta and the wider identity industry
Enterprise Managed AuthClaude's connector feature that implements all of the aboveAnthropic
Claude-issued, or auto-connectThe option where Claude signs the assertion instead of an identity provider. In betaAnthropic

Claude-issued or identity provider-issued?

Claude can present an assertion signed by either. The token format and the exchange are the same, and each workspace trusts one issuer. The differences are in what the assertion proves and how you find the person.

Claude-issuedIdentity provider-issued
Who signs itClaude, under a URL unique to the Claude organizationThe customer's identity provider, under its own URL
AvailabilityBeta, Team and EnterpriseGenerally available, Team and Enterprise
What the customer needsNothing extra. No SSO or verified domainSSO into Claude through their identity provider, such as Okta
Not offered whenThe organization signs in to Claude through OktaThe organization has no identity provider
How to find the userBy email. The sub is opaque and differs per issuerBy iss and sub, which match your SSO subject
email claimAlways present, lowercaseOptional
What it provesCurrent membership of the Claude organization. No SSO, MFA or group claimsWhatever the identity provider's policy enforced

Build Claude-issued first. A Team organization you create for testing qualifies as it is, so you can test the same day. It is also the only option if your product has no SSO to match a subject against, which was our situation.

What happens at sign-in

  • Claude calls one of your tools with no token, and your MCP server answers 401 with a WWW-Authenticate header pointing at your protected resource metadata.
  • Claude reads that metadata, then your authorization server metadata, and sees the JWT bearer grant listed.
  • If the organization has set this up for your connector, Claude posts a signed assertion to your token endpoint instead of showing a Connect card.
  • You validate it and return an access token.
  • Claude retries the tool call with that token. The person sees nothing.

The request looks like this:

http
POST /oauth/token HTTP/1.1
Host: auth.northstar.example
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&assertion=eyJhbGciOiJFUzI1NiIs...
&client_id=https://claude.ai/oauth/mcp-oauth-client-metadata
&resource=https://mcp.northstar.example

And the decoded assertion has this shape:

json
{
  "iss": "https://identity.anthropic.com/issuers/4f1c9b7a",
  "sub": "an-opaque-value-that-differs-per-issuer",
  "email": "alex@northstar.example",
  "aud": ["https://auth.northstar.example"],
  "client_id": "https://claude.ai/oauth/mcp-oauth-client-metadata",
  "iat": 1793750000,
  "nbf": 1793749985,
  "exp": 1793750045,
  "jti": "a-unique-id-you-may-accept-once"
}

aud_tenant appears too if the customer's admin entered your tenant ID. scope is optional.

Step 1: change your authorization server metadata

Claude reads your RFC 8414 metadata and only sends assertions if the grant is listed, even if your token endpoint would already accept it.

json
{
  "issuer": "https://auth.northstar.example",
  "token_endpoint": "https://auth.northstar.example/oauth/token",
  "grant_types_supported": [
    "authorization_code",
    "refresh_token",
    "urn:ietf:params:oauth:grant-type:jwt-bearer"
  ],
  "token_endpoint_auth_methods_supported": ["none"],
  "client_id_metadata_document_supported": true
}

The jwt-bearer entry and the last line are the additions. Three rules come with them:

  • issuer has to match the URL the metadata was fetched from.
  • token_endpoint has to share a registrable domain with issuer, and has to answer at that exact URL, because Claude does not follow redirects on this request.
  • Keep issuer byte for byte as published, trailing slash included. It is the audience of every assertion, and a Claude-issued setup records it, so changing it later stops sign-ins for that customer.

Claude caches this document for about five minutes, so allow for that when testing a change.

Step 2: support Client ID Metadata Documents

This is the part that surprises people, and it is bigger than it looks.

Every assertion carries a client_id, and your server has to recognize that client before the first one arrives. A client created through Dynamic Client Registration gets a generated id that can never match, so DCR is out. Your options are Anthropic-held client credentials or a Client ID Metadata Document, where the client_id is an HTTPS URL and the document at that URL describes the client. Claude's is at https://claude.ai/oauth/mcp-oauth-client-metadata, and its grant_types already lists the JWT bearer grant.

Claude picks CIMD only when your metadata has both client_id_metadata_document_supported: true and "none" in token_endpoint_auth_methods_supported. Otherwise it falls back to DCR.

The catch: once you advertise it, every host that supports it switches to it for new connections, for ordinary interactive sign-in as well. So this has to work end to end at your authorization endpoint, not just at the token endpoint. Connections people already made through DCR keep working, as long as you keep DCR running beside it.

What we check when a client_id is a URL:

  • It is https, has a path, carries no credentials or fragment, and is spelled canonically, because the document has to name itself exactly.
  • The document's own client_id field equals the URL, it lists redirect_uris, and it does not claim a confidential auth method.
  • The requested redirect_uri matches the document exactly, except that loopback addresses match on any port. Claude Code and VS Code both publish loopback addresses and bind whatever port is free when they run (RFC 8252, section 7.3).
  • The consent screen names the URL's host as the app, not the document's client_name. The document is self-asserted, and the host is the only part you verified.

Do not validate the document's grant types strictly. People are already hitting this one. Claude's document lists three grant types: authorization_code, refresh_token and the JWT bearer grant. VS Code's lists the device code grant. A client publishes one document for every server it talks to and cannot tailor it to yours, so an entry you do not support tells you nothing about whether it can use your server. A resolver that treats that entry as fatal refuses the whole document, and the person just sees a failed connection.

Here is how it has shown up, as of November 2026:

WhereWhat you seeStatus
django-oauth-toolkitclient metadata must declare exactly one non-refresh grant type, surfacing at the authorize step as Invalid client_id parameter valueFixed in its repository, not yet in a release as of 3.4.1
Oracle OCI IAM identity domainsinvalid_cimd_requestOpen
ToolHive, with VS Code's documentinvalid_client: The requested OAuth 2.0 Client does not existFixed

The fix is to drop the entries you do not issue, and refuse the document only if nothing you need remains:

ts
const WE_ISSUE = new Set(["authorization_code", "refresh_token", JWT_BEARER_GRANT]);
const declared = Array.isArray(doc.grant_types) ? doc.grant_types : ["authorization_code"];
const grants = declared.filter((grant) => WE_ISSUE.has(grant));
if (!grants.includes("authorization_code")) throw new Error("no flow we support");

Ours does not read the field at all, because what a client may do is decided by the token request and the checks on it, not by what its document declares. If you are on a hosted identity platform that rejects the document, you cannot fix it from your side, because Anthropic hosts it. Raise it with your vendor, and follow the Oracle issue above.

You are also now fetching a URL an unauthenticated stranger chose, from your own server, so treat it like a webhook destination: refuse addresses that resolve to private ranges, refuse redirects, cap the size, set a short timeout, cap how many you fetch per minute, and cache the result, including failures. We also refuse client_id URLs on our own domains. Customers' apps live under ours, and "someone.apps.ourdomain.com wants to connect" reads as us.

If your codes or refresh tokens have a foreign key to a clients table, store a row at the moment someone approves, not when the document is first read. Otherwise anyone can fill the table by asking.

Step 3: let an admin register the issuer

Give each workspace's admins one field for the trusted issuer URL, and show your tenant ID beside it if you have one. Only admins may set it, and it should be logged like the access decision it is. The admin copies the URL from the Issuer URL box in Claude's Managed authorization setup for your connector. Linear's setup is a good public example of the flow from a customer's side.

Accept only a URL you are willing to fetch. If you support Claude-issued assertions and nothing else, as we do today, validate the field against that exact shape. That removes a whole class of problem: an admin's input never becomes an arbitrary URL your server reaches out to, and nobody can point a workspace at an identity provider of their own and have it vouch for any address it likes.

Step 4: run the nine checks, in order

First find the one workspace the assertion is for: the one aud_tenant names, or otherwise the only one that registered iss. Everything before the signature check is reading unverified claims, and choosing where to look is the only thing you may use them for. Any failure below returns invalid_grant.

#CheckWhat goes wrong without it
1iss exactly equals the workspace's registered issuer, before fetching any keyA prefix or host match admits other customers' users, and an unknown issuer makes you fetch from it
2Keys come from <iss>/.well-known/openid-configuration, whose issuer must equal iss, then its jwks_uriTrusting a key or key URL from the JWT's own header means trusting the attacker
3Signature verifies. Accept ES256 and RS256 onlynone and HMAC algorithms are the classic forgeries. Claude-issued assertions use ES256
4The typ header is oauth-id-jag+jwtA different kind of token signed by the same issuer gets through
5aud is your own issuer, as a string or a one-element arrayAn assertion meant for another service works on yours
6The client_id claim equals the request's client_idAn assertion issued to one client is spent by another
7sub is presentMalformed assertions pass
8exp has not passed, iat is not in the future, nbf has passed, with at most 60 seconds of skewOld or not-yet-valid assertions work
9jti is present and has never been used by this issuerA captured assertion works twice. If you cannot check, refuse

Two details that only show up when you build it:

  • A Claude issuer's discovery document is not a full OpenID configuration. It holds issuer and jwks_uri, with no authorization_endpoint or token_endpoint, so a library that validates the whole document will reject it. Read those two fields yourself, then build the key set from jwks_uri.
  • Make the replay check atomic. A primary key on issuer and jti, with an insert that does nothing on conflict, means two simultaneous exchanges of one assertion cannot both win. Each row only has to live until the assertion's expiry plus your skew, which for Claude is about a minute.

Step 5: find the person, and be strict about it

For a Claude-issued assertion, find the user by email.

  • Compare the whole address, ignoring case. Keep dots and plus tags as they are.
  • Look only among the members of the workspace the assertion resolved to.
  • Sign someone in by email only if you have verified that address yourself, or the address is on a domain the workspace has verified.
  • If nobody matches, refuse. Create a user only for an address on a domain the workspace has verified. We have no verified domains, so we create nobody, and the admin invites people first.

Then answer with a normal token response, including expires_in, and no refresh token. Claude does not use one from this grant. When the access token runs out it gets a new assertion and exchanges it again, with nothing for the person to do, so a short lifetime costs nothing. An hour is reasonable. Keep issuing refresh tokens in your interactive flow.

The whole exchange, in code

This is the logic from our token endpoint, condensed and using jose. Use a real JWT library rather than verifying signatures yourself. db stands in for your own data layer, and at the route you turn any thrown error into invalid_grant.

ts
import { createRemoteJWKSet, decodeJwt, jwtVerify, type JWTVerifyGetKey } from "jose";

// Your metadata's `issuer`, byte for byte. It is every assertion's audience.
const OUR_ISSUER = "https://auth.northstar.example";
const CLAUDE_ISSUER = /^https:\/\/identity\.anthropic\.com\/issuers\/[A-Za-z0-9][A-Za-z0-9._~-]*$/;

const keySets = new Map<string, JWTVerifyGetKey>();

async function keysFor(iss: string): Promise<JWTVerifyGetKey> {
  const cached = keySets.get(iss);
  if (cached) return cached;
  const res = await fetch(`${iss}/.well-known/openid-configuration`, {
    redirect: "error",
    signal: AbortSignal.timeout(4_000),
  });
  const doc = await res.json();
  if (doc.issuer !== iss) throw new Error("discovery names a different issuer");
  // Refetches by itself when an assertion names a key it has not seen.
  const keys = createRemoteJWKSet(new URL(doc.jwks_uri), { timeoutDuration: 4_000 });
  keySets.set(iss, keys);
  return keys;
}

export async function exchangeAssertion(assertion: string, clientId: string) {
  // Unverified, and used for one thing: deciding where to look.
  const claims = decodeJwt(assertion);
  const iss = String(claims.iss ?? "");
  const workspace =
    typeof claims.aud_tenant === "string"
      ? await db.workspaceById(claims.aud_tenant)
      : await db.onlyWorkspaceTrusting(iss); // null for none, and for more than one

  // 1. Issuer: an exact match, before any key is fetched.
  if (!workspace || workspace.trustedIssuer !== iss || !CLAUDE_ISSUER.test(iss)) {
    throw new Error("issuer is not registered for one workspace");
  }

  // 2 to 5, 7 and 8.
  const { payload } = await jwtVerify(assertion, await keysFor(iss), {
    issuer: iss,
    audience: OUR_ISSUER,
    algorithms: ["ES256", "RS256"],
    typ: "oauth-id-jag+jwt",
    clockTolerance: 60,
    requiredClaims: ["exp", "iat", "sub", "jti"],
  });
  // jose only reads iat when given a maximum age, so this one is yours.
  if (payload.iat! > Date.now() / 1000 + 60) throw new Error("iat is in the future");

  // 6. Client.
  if (payload.client_id !== clientId) throw new Error("issued to a different client");

  // 9. Replay. Last, so a refused assertion does not use up its id.
  const firstUse = await db.spendJti(iss, payload.jti!, payload.exp! + 60);
  if (!firstUse) throw new Error("already used");

  // The person: a verified address, a member of this workspace, and nobody else.
  const user = await db.userByEmail(String(payload.email ?? ""));
  if (!user?.emailVerified || !(await db.isMember(workspace.id, user.id))) {
    throw new Error("no verified member with that email");
  }

  // Good for this one workspace, whatever else the person belongs to.
  return issueAccessToken({ user, workspace, clientId, expiresIn: 3600 });
}

Write error_description values an admin can act on. Claude's connection test shows them directly, so "No verified teammate on this account has that email address" saves a support ticket.

Six mistakes to avoid

1. Matching on the subject because the spec says to. The MCP extension's guidance says to use the subject as the primary identifier and fall back to email. That is right for an identity provider. For a Claude-issued assertion it fails every time: the sub is opaque, differs per issuer, and will never match anything you hold. Use the email, and only when verified.

2. Putting a unique index on the issuer column. It feels like good hygiene. But an issuer URL is not a secret, so a unique index lets anyone lock a customer out of their own setup by registering their URL first. Allow duplicates, refuse the assertion when more than one workspace registered its issuer, and let the customer's admin resolve it with your tenant ID, which arrives as aud_tenant.

3. Falling back to the person's own account. This one is not on any checklist, because it depends on your code. Our MCP endpoint resolves which account a token acts on, and that lookup falls back to the person's own account when they are no longer a member of the requested one. For an API key that is right: a stale account id shows you your own things instead of someone else's. For a token earned by an assertion it would have been a hole. Someone removed from a team would keep a working token, now pointed at a personal account nobody ever consented to. So these tokens carry the issuer that earned them, and every call checks that the person still has a role on that exact account and that the account still trusts that issuer. There is no fallback. It also means an admin turning the feature off takes effect on the next request rather than within the hour.

4. Advertising CIMD before your authorization endpoint handles it. The flag changes every compatible host's behavior for new connections, not just this flow. A half-finished version breaks ordinary sign-in.

5. Trusting any issuer that looks right. Matching on a prefix or host admits every other customer of that issuer. And if you accept arbitrary issuers while matching by email, an issuer URL someone registered in a workspace they control can vouch for any address it likes.

6. Not refusing a viewer. If your product has a read-only role, decide what an assertion means for it. Membership of the workspace is not the same as permission to use your tools. We refuse viewers, because every tool we expose is a build tool.

How to test it

Start with Claude-issued assertions, because a Team organization you create for testing qualifies with no SSO, verified domain or identity provider. Do not use an organization that signs in to Claude through Okta, where the option is not offered.

  • Add your MCP server as a custom connector for the organization, signed in as an Owner.
  • Open the connector, click Set up on the Managed authorization row, and choose Claude-issued under Identity source.
  • Copy the Issuer URL into a test workspace in your product, and enter your tenant ID in Claude if you use one.
  • Click Run test. It shows which step failed, what Claude sent and what came back, and the decoded claims.

For the identity provider flow, Okta's Cross App Access sandbox exercises your server without a Claude organization at all.

Before launch, make sure each of these is refused, not only that the happy path works:

  • An iss no workspace registered.
  • An iss registered by two workspaces, with no tenant ID.
  • An aud_tenant naming a workspace that registered a different issuer.
  • The same assertion a second time.
  • An aud that is not your issuer.
  • A correct assertion for an address you have not verified, on a domain the workspace has not verified.

Troubleshooting

What you seeLikely causeFix
Invalid client_id, invalid_client or invalid_cimd_request at the authorize step, as soon as CIMD is onYour CIMD code refuses Claude's document because it lists the JWT bearer grantDrop grant types you do not issue, and refuse only if nothing you need remains. See Step 2
Claude shows a Connect card instead of connecting silentlyThe grant is missing from grant_types_supported, or the organization has not finished setupList the grant even if the endpoint already accepts it, and allow five minutes for the cache
No Managed authorization row on the connectorIt was added from the directory, and the listing is not marked as supporting thisTest as a custom connector at the same URL
Claude registers through DCR instead of using its metadata URLOne of the two CIMD values is missing from your metadataAdvertise client_id_metadata_document_supported: true and "none" in the auth methods
invalid_client on the token requestYour server cannot fetch or accept Claude's client documentCheck outbound access to claude.ai, and that the fetch is not refused by your private-address or size limits
Your MCP server gets the request, but your authorization server sees nothingDiscovery is failing, often a firewall in front of itCheck the resource_metadata pointer on your 401, and allow Anthropic's egress range, 160.79.104.0/21
invalid_grant on every assertion, signature fineaud mismatch, often a trailing slashCompare aud with your metadata's issuer, byte for byte
Key lookup failsA validator expects a full OpenID configurationRead issuer and jwks_uri from the document yourself
Works for one person, fails for anotherTheir Claude email differs from their account, or it is unverifiedMatch the addresses, and verify the email on your side
Works, then fails intermittentlySlow token endpointClaude waits 10 seconds. Cache the keys and the client document

Do you have to build this yourself?

Not necessarily. The MCP documentation keeps a list of products that accept ID-JAGs, including Okta, Descope, Stytch, Auth0 and WorkOS AuthKit (the last two in early access), Keycloak (experimental), and frameworks such as Cloudflare's workers-oauth-provider and FastMCP.

Before you rely on one for Claude-issued assertions, check three things: it runs every check in the table above, it can register an issuer URL that does not belong to a customer's identity provider, and it can find a user by email rather than by SSO subject. A platform built around identity providers may not do the last two. We run our own authorization server, so we built it directly.

Which connectors support it?

At launch in November 2026, the Claude-issued beta listed fourteen: Amplitude, Apollo.io, Atlassian, Datadog, Dropbox, Figma, Granola, HubSpot, Linear, Mixpanel, Notion, PagerDuty, Semrush and Supabase. A server not on the list can still implement this and test it through a custom connector.

Getting your connector listed

Implementing it does not change your directory listing on its own. Once your server passes end to end:

  • Publish a setup guide for your customers' admins, including how to enter a Claude issuer URL. Claude links to it from the admin console. Ours is a template if you want one: four steps, what the feature does and does not vouch for, and what each error means.
  • Add the guide's URL to your directory listing.
  • Email mcp-review@anthropic.com with your listing's name and which kinds of assertion you accept.

FAQ

What is Claude plugin auto-connect?

It is Claude connecting a plugin for members of an organization at login, with no sign-in page or consent screen. It works when the plugin's MCP server accepts Claude as a trusted issuer, and an admin has set it up on both sides. It is in beta on Claude's Team and Enterprise plans.

What does it mean for an MCP server to accept Claude as a trusted issuer?

A customer's admin registers their Claude organization's issuer URL in your product. When Claude then presents a signed identity assertion from that URL, your authorization server validates it and returns an access token, instead of sending the person through a consent screen.

What is the Claude issuer URL?

It has the form https://identity.anthropic.com/issuers/ followed by an id that is unique to each Claude organization and is not the organization's ID. An admin copies it from the Managed authorization setup for your connector in Claude.

Is Claude-issued the same as Enterprise Managed Auth?

It is one of two options inside it. Enterprise Managed Auth is the overall feature, where Claude presents a signed assertion instead of an interactive sign-in. The assertion is either signed by the customer's identity provider or, with the Claude-issued option, by Claude.

Does this work with Dynamic Client Registration?

No. Your server has to recognize the client_id before the first assertion, and a DCR client's generated id can never match. Support Client ID Metadata Documents or Anthropic-held credentials. You can keep DCR running for everything else.

Why does my server reject Claude's client metadata document?

Usually because the document lists the JWT bearer grant alongside authorization_code and refresh_token, and your code refuses any grant type it does not support. It often shows up as Invalid client_id or invalid_client at the authorize step. Drop the entries you do not issue, and refuse the document only if nothing you need remains.

Why not find the user by the sub claim?

Because a Claude-issued sub is opaque and differs under each issuer, so it never matches a subject you already hold. Find the user by email, among the members of that workspace, and only if the address is verified. For an identity provider-issued assertion, use iss and sub instead.

Do I need to issue refresh tokens for the JWT bearer grant?

No, and you should not. Claude requests a new assertion each time the access token expires, with nothing for the person to do. Keep refresh tokens for your interactive flow.

Does it work with lazy authentication?

Yes. If some of your tools need no account, the 401 on a protected tool triggers the silent exchange instead of a Connect card. A fully authless server never returns a 401, so this cannot apply to it.

Does a Claude-issued assertion prove the person used SSO or MFA?

No. It proves current membership of the Claude organization and the email on that account, and it carries no group claims. If a customer needs SSO enforced, their identity provider has to issue the assertion instead.

What happens when someone leaves the company?

Claude stops signing assertions once they are removed from the Claude organization, but any access token you already issued lives until it expires. Short lifetimes bound that, and customers should remove the person on your side too.

External references

About Server4Agent

Server4Agent is a hosted server for AI agents. Your assistant builds a tool, site, API or bot on it from a plain-English request and ships it to a live URL, private by default and under a hard budget cap. Admins can connect a whole team from Claude with the setup guide.

Questions, or a tool you want built?

Ask us about this post, or tell us what you would hand to an assistant first. A person reads every message and answers within one business day.