Skip to main content

Identity API

Aspire name api-identity. The only service that signs tokens.

Internal only

No endpoint here enforces a permission — every one exists to establish an identity that does not yet exist, so requiring a token would fail the very request that issues one. This service must not be reachable from outside the cluster.

Mint a token from a login

POST /generatejwt
{
"userId": "9c1e7a4d-…",
"provider": "Entra",
"providerUserId": "…",
"name": "Neil Docherty",
"email": "neil@example.com",
"orgId": "05cc0c65-…",
"profileImage": null
}

Returns the token as text/plain.

StatusMeaning
200The token
403There is nobody to issue a token to, and no account pattern permits creating them. Not a fault in the request — the caller should end the session, not report a problem with it.
400The request was wrong

The generator reads the account and its permissions from the account API, then mints. sub is the TagShape account ID, not the provider's identifier. Where the account exists, its name and email win over what the provider said, so a rename reaches the token on the login that noticed it.

Renew a token

POST /refreshjwt
{ "userId": "9c1e7a4d-…", "orgId": "05cc0c65-…" }

Re-reads permissions from GET /users/{id}/permissions before minting, so a permission granted or withdrawn takes effect at the next refresh. Creates nothing and changes nothing — provisioning only ever happens on a login.

Exchange an API key

curl -i -X POST "$IDENTITY_API/apikeyjwt" -H "x-tagshape-api: $API_KEY"
HTTP/1.1 200 OK
x-tagshape-auth: eyJhbGciOiJSUzI1NiIs...

The key travels in a header so the exchange looks like every other call the caller makes, and the token comes back in one for the same reason.

StatusMeaning
200Token in x-tagshape-auth
401No key, a key that named nobody, a revoked key, or an expired key — all the same answer, so nothing tells a prober which of their guesses was once real
500The key was accepted but signing failed. Deliberately not a 401, which would send somebody off rotating a key that was fine.

A token minted from a key is indistinguishable from one minted from a login. It cannot ask for a session as somebody else, or in an organization that is not its own.

Generate a signing key

curl "$IDENTITY_API/generatejwk/my-key-id"

Returns a public PEM, a private PEM and a JWK. An operational tool run out of band — not part of the request path. The private PEM becomes Jwt:PrivateKey on this service.

Signing and lifetime

RS256. Configured under Jwt:

SettingDefault
Issuerauth@tagshape.com
Audiencetagshape.com
DurationInMinutes60
RefreshDurationInMinutes10080
PrivateKey(required)

See JWT for the claim set and Configuration.

Auditing

Every mint writes a JWT audit entry with the action Create or Refresh. Those written during a login belong to no organization yet, which is why reading them needs AuditGlobalList and AuditGlobalRead rather than the organizational pair — see Audit entries.