Token samples
One real example of every kind of token, assertion and certificate this
service issues, decoded. They were captured from a running
development-mode container reached at https://127.0.0.1:38081, so
127.0.0.1:38081 in a value below is the address the request arrived on.
That address becomes the issuer, and yours will differ. Every value was
produced by the service. Nothing here was written by hand, apart from the
cuts listed below.
Cuts. Long base64 values are shortened with … wherever a token is shown
decoded. That covers JWT signatures, XML SignatureValue, DigestValue and
X509Certificate, and the hex dumps in certificates. XML is re-indented for
reading, so a pretty-printed signed document no longer verifies; the
signature covers the bytes as sent. The OAuth access token and the ID Token
are the exceptions: they are given encoded in full as well.
Two starts. Most samples come from one start of the service. The
ones marked second start were added later from a fresh start of the same
image, so their signing keys (kid), certificates and serial numbers
differ from the rest.
None of these verify today. In development mode every key, certificate
authority and session is made again at each start, so the keys that signed
these samples no longer exist. To make your own, run the requests shown with
each sample against your instance and paste the result into any JWT or ASN.1
decoder. Which door accepts which token is covered in
Accepted tokens; every endpoint is listed live at
/admin/sts-metadata.
The person in every sample is alice, a seeded development user whose stable
subject is urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2 (the
entryUUID of the directory entry). Development mode checks no password,
so password=x is enough wherever one is asked for. It also accepts any
client_id, so demo, ssf-rx and wallet below are names made up
for the request, not registered clients.
- OAuth 2.0 access token
- OpenID Connect ID Token
- Other JWTs: refresh token, token exchange, RFC 9701 introspection response, UserInfo JWT, back-channel Logout Token, WS-Trust JWT, software statement, signed metadata
- SAML 2.0 assertion, artifact, ArtifactResponse and signed metadata
- SAML 1.1 assertion and artifact
- WS-Federation and WS-Trust responses
- Shared Signals: SSF, CAEP and RISC
- Verifiable credentials and status lists, the OpenID4VP request object, the Domain Linkage Credential and a Credential Offer
- GNAP access tokens
- SPIFFE SVIDs
- X.509 certificates, CRLs and OCSP, including ACME and SCEP
- Kerberos tickets, keytabs and SPNEGO
- Second factors: TOTP and recovery codes
- Opaque values
OAuth 2.0 access token
An RFC 9068 JWT access token, in
every mode: typ is at+jwt, it is signed with the realm key published at
/oauth2/jwks, and x5u names that key’s certificate chain under
/pki/chain/. This one came from the authorization code flow (a browser at
/oauth2/authorize, the sign-in screen, the consent screen, then):
curl -X POST https://127.0.0.1:38081/oauth2/token \
-d grant_type=authorization_code -d client_id=demo \
-d code=qVqFgarG41wqzJk_HdOcC9ZJoLT5iY4A \
-d redirect_uri=https://client.example.org/cb
Encoded:
eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCIsImtpZCI6InN0cy1mNzA0NTI0MWU2YjAiLCJ4NXUiOiJodHRwczovLzEyNy4wLjAuMTozODA4MS9wa2kvY2hhaW4vZGVmYXVsdC84ZjFlMTljZmVlYzNkNTZjNDk5ODI1YjFlZjcwOTQ5NjExNjYxOTg0NjNiMTRlMzAxOTE0YmVmNTk1YzE5OWRjLnBlbSJ9.eyJncm91cHMiOlsiZGV2ZWxvcGVycyJdLCJpc3MiOiJodHRwczovLzEyNy4wLjAuMTozODA4MSIsInN1YiI6InVybjp1dWlkOjAxNmRjOGYxLTFiYzQtNTVkOS05NjU3LTliMmViYjNjZDRkMiIsImF1ZCI6Imh0dHBzOi8vMTI3LjAuMC4xOjM4MDgxL3Jlc291cmNlIiwiY2xpZW50X2lkIjoiZGVtbyIsInR5cCI6IkJlYXJlciIsImp0aSI6IklINVBZNTNUWkUtb25EM01qZ2gzbEEiLCJpYXQiOjE3OTAxMTA0OTMsIm5iZiI6MTc5MDExMDQ5MywiZXhwIjoxNzkwMTE0MDkzLCJ1c2VybmFtZSI6ImFsaWNlIiwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSIsInByZWZlcnJlZF91c2VybmFtZSI6ImFsaWNlIiwiYXV0aF90aW1lIjoxNzkwMTEwNDc2LCJhbXIiOlsicHdkIl0sImFjciI6IjEifQ.p13KXOIHRnuBr9kLHJF3iYLnQy8iVA0HPQX1xvuwm2j02_WfS8TFhla4sNpWRCIsUQlT3NFlpwwxEZSDJNT6jSUr2uUhI-qQ0pshHynmnfI6J3b2WXpLVzOw-F2eOx1KD9ZHrKpgD5nNIKAoJ3IrT3IcR-z0A3FDyuy6UfUhVlcR8WQREhw6oJMYf4nT4zP_I-outC5wjPtZeR7Vd882dtePp8opkVaocOo4Uu5gS9BL-T-CDkLgP8aj3T64Vx0fb9JQZKTCXmb1wUsteNb684Td_2Z5hL-l_HpJbGLnXRNeVIrNyEPEu1e6c5ZcubSAtN7I0Z6y0fyMJH614WtWhw
Header:
{
"alg": "RS256",
"typ": "at+jwt",
"kid": "sts-f7045241e6b0",
"x5u": "https://127.0.0.1:38081/pki/chain/default/8f1e19cfeec3d56c499825b1ef7094961166198463b14e301914bef595c199dc.pem"
}
Payload:
{
"groups": [
"developers"
],
"iss": "https://127.0.0.1:38081",
"sub": "urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2",
"aud": "https://127.0.0.1:38081/resource",
"client_id": "demo",
"typ": "Bearer",
"jti": "IH5PY53TZE-onD3Mjgh3lA",
"iat": 1790110493,
"nbf": 1790110493,
"exp": 1790114093,
"username": "alice",
"scope": "openid profile",
"preferred_username": "alice",
"auth_time": 1790110476,
"amr": [
"pwd"
],
"acr": "1"
}
Claims worth knowing:
subis the person’s stable subject,urn:uuid:<entryUUID>, never the user name. The user name is inusernameandpreferred_username.audis the default resource,{issuer}/resource, unless the request named one withresource(RFC 8707). The token exchange sample below names another.typinside the payload (Bearer) is this service’s own marker. Its doors read it to tell an access token from an ID Token or a refresh token, all three being signed by one key.auth_time,amrandacrare copied from the session. Aclient_credentialstoken has none of them, and nousernameorpreferred_usernameeither: it is about no person. Itssubis the client application (theclient_id, orurn:sts:client:<client_id>in RFC 9700 mode), and itsrolesare the roles the application holds as itself (roleMemberApplication), with the roles of the application it is for.groupscomes from the person’s directory groups.
OpenID Connect ID Token
Issued beside the access token above, from the same token response. Its
typ header is JWT.
This sample was captured before #118 and shows the earlier shape. An ID Token from the authorization code flow no longer carries:
- the payload member
typ: "ID", which no specification defines. An ID Token has notypmember now, while an access token carriestyp: "Bearer"and a refresh tokentyp: "Refresh", and that is how the two are still told apart. - the profile and email claims. OpenID Connect Core section 5.4 returns them
from UserInfo when an access token is issued, and in the ID Token only for
response_type=id_token. - an
auth_timewhen the time of authentication is not known.
at_hash is now computed with the hash of the ID Token’s own alg.
Encoded:
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InN0cy1mNzA0NTI0MWU2YjAiLCJ4NXUiOiJodHRwczovLzEyNy4wLjAuMTozODA4MS9wa2kvY2hhaW4vZGVmYXVsdC84ZjFlMTljZmVlYzNkNTZjNDk5ODI1YjFlZjcwOTQ5NjExNjYxOTg0NjNiMTRlMzAxOTE0YmVmNTk1YzE5OWRjLnBlbSJ9.eyJncm91cHMiOlsiZGV2ZWxvcGVycyJdLCJpc3MiOiJodHRwczovLzEyNy4wLjAuMTozODA4MSIsInN1YiI6InVybjp1dWlkOjAxNmRjOGYxLTFiYzQtNTVkOS05NjU3LTliMmViYjNjZDRkMiIsImF1ZCI6ImRlbW8iLCJ0eXAiOiJJRCIsImlhdCI6MTc5MDExMDQ5MywibmJmIjoxNzkwMTEwNDkzLCJleHAiOjE3OTAxMTQwOTMsImF1dGhfdGltZSI6MTc5MDExMDQ3NiwiYXpwIjoiZGVtbyIsImp0aSI6IkVsOWhzNUhaNHhfSUg2YzNXOGxrOUEiLCJuYW1lIjoiYWxpY2UgKG1vY2spIiwiZ2l2ZW5fbmFtZSI6ImFsaWNlIiwiZmFtaWx5X25hbWUiOiJNb2NrIiwicHJlZmVycmVkX3VzZXJuYW1lIjoiYWxpY2UiLCJlbWFpbCI6ImFsaWNlQGV4YW1wbGUuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImFtciI6WyJwd2QiXSwiYWNyIjoiMSIsIm5vbmNlIjoibjEiLCJzaWQiOiJzSGlLbUhCa09KNmJqS1hNLVRuRm9IelpQRVBJekhTNyIsImF0X2hhc2giOiJVVk9QdTAxY1NxQWlUT1d4YjFUdExBIn0.fCwfKe7lc77252_ukLrVgC4xvmOXcXTxdWo4aY8_VKyY7RVJyOUJ8no1qytXk-JzMCFFjiMkHPpWnDW3izWimFZ3RbNEygi5WNglfLpucqbCvHDU69u6jEtTVkuzAErGv3XPiHrHzor7loyzOtSBDJqDjb4PrHdZR6fY1gBZniwap-LcrHgTsDRIfRizc6Y3Pw0E4SSgIcTYmAgFF4b8bkoLNiwpmTOLzuANtG8gVSFvTJJJmwAoA9inP2HsBz49YPefbtDSLw5Yl4J-0Zk_i4vpN_b9ygk_CIK6sK8ihIctZL8WzmOqg0dkSsJrboVAOutQ-1IR1s9Da0ys9kkgNA
Header:
{
"alg": "RS256",
"typ": "JWT",
"kid": "sts-f7045241e6b0",
"x5u": "https://127.0.0.1:38081/pki/chain/default/8f1e19cfeec3d56c499825b1ef7094961166198463b14e301914bef595c199dc.pem"
}
Payload:
{
"groups": [
"developers"
],
"iss": "https://127.0.0.1:38081",
"sub": "urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2",
"aud": "demo",
"typ": "ID",
"iat": 1790110493,
"nbf": 1790110493,
"exp": 1790114093,
"auth_time": 1790110476,
"azp": "demo",
"jti": "El9hs5HZ4x_IH6c3W8lk9A",
"name": "alice (mock)",
"given_name": "alice",
"family_name": "Mock",
"preferred_username": "alice",
"email": "alice@example.com",
"email_verified": true,
"amr": [
"pwd"
],
"acr": "1",
"nonce": "n1",
"sid": "sHiKmHBkOJ6bjKXM-TnFoHzZPEPIzHS7",
"at_hash": "UVOPu01cSqAiTOWxb1TtLA"
}
audandazpare the client,demo.nonceechoes the authorization request’snonce=n1.sidis the sign-on session, the same value that appears as the SAMLSessionIndex, in the CAEP events’sessionsubject and in the Logout Token below. The ID Token, SAML 2.0, SAML 1.1 and WS-Federation samples all came from this one session.at_hashis the left half of the SHA-256 of the access token, SHA-256 being RS256’s hash (OIDC Core 3.1.3.6).name,given_name,family_name,emailandemail_verifiedare invented in development mode (mode.inventsClaimValues()), which is why the family name isMock. Product mode fills them only from the directory entry, andemail_verifiedistrueonly when the person verified that address by following a link sent to it (mail),falseotherwise.emailis here although the request asked only foropenid profile. That was a bug, #155, fixed by #118: none of these claims are in a code-flow ID Token now.
Other JWTs
Refresh token
A refresh token is a nested JWT: the signed JWT is encrypted to a key only
this service holds, so a client cannot read it. Only the JWE header is
readable. It is five dot-separated parts, not three. From the password grant
with offline_access:
curl -X POST https://127.0.0.1:38081/oauth2/token \
-d grant_type=password -d client_id=demo -d username=alice -d password=x \
-d 'scope=openid profile email offline_access'
Encoded (shortened):
eyJhbGciOiJSU0EtT0FFUC0yNTYiLCJlbmMiOiJBMjU2R0NNIiwidHlwIjoi…TkQSKXuj_h5vWvDX-Cfg
JWE header:
{
"alg": "RSA-OAEP-256",
"enc": "A256GCM",
"typ": "JWT",
"cty": "JWT",
"kid": "sts-rt-rsa-qs7d_OUa3sImlIYA"
}
Token exchange (RFC 8693)
The access token above, exchanged for one audienced to another API.
Development mode does not verify the subject_token; product mode does.
curl -X POST https://127.0.0.1:38081/oauth2/token \
-d grant_type=urn:ietf:params:oauth:grant-type:token-exchange \
-d client_id=demo -d subject_token=$ACCESS_TOKEN \
-d subject_token_type=urn:ietf:params:oauth:token-type:access_token \
-d audience=https://api.example.org
Response (tokens shortened):
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6Im…WgQY_nzkzS2Jvz3aUyWg",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "",
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6Ik…pbF4jTS4SWDAXv04ZEig",
"issued_token_type": "urn:ietf:params:oauth:token-type:access_token"
}
Issued access token payload:
{
"groups": [
"developers"
],
"iss": "https://127.0.0.1:38081",
"sub": "urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2",
"aud": "https://api.example.org",
"client_id": "demo",
"typ": "Bearer",
"jti": "-fpFs1wXvCNyFLlgASNYBw",
"iat": 1790110709,
"nbf": 1790110709,
"exp": 1790114309,
"username": "alice",
"preferred_username": "alice"
}
The empty scope and the unrequested id_token are a bug,
#156.
Introspection response as a JWT (RFC 9701)
Asked for with Accept: application/token-introspection+jwt. The caller must
authenticate for this in every mode, so the sample used a confidential client
registered at /oauth2/register. The response is signed. It carries no sub
or exp of its own, so it cannot be replayed as a token (RFC 9701 section 5).
curl -X POST https://127.0.0.1:38081/oauth2/introspect \
-u "$CLIENT_ID:$CLIENT_SECRET" \
-H 'Accept: application/token-introspection+jwt' -d token=$ACCESS_TOKEN
Encoded (shortened):
eyJhbGciOiJSUzI1NiIsInR5cCI6InRva2VuLWludHJvc3BlY3Rpb24rand0…8dnnk0d02hTEGwLGQItA
Header:
{
"alg": "RS256",
"typ": "token-introspection+jwt",
"kid": "sts-f7045241e6b0",
"x5u": "https://127.0.0.1:38081/pki/chain/default/8f1e19cfeec3d56c499825b1ef7094961166198463b14e301914bef595c199dc.pem"
}
Payload:
{
"iss": "https://127.0.0.1:38081",
"aud": "sts-client-L2a5XvtDkIM",
"iat": 1790110888,
"token_introspection": {
"active": true,
"scope": "openid profile",
"client_id": "demo",
"username": "alice",
"token_type": "Bearer",
"exp": 1790114488,
"iat": 1790110888,
"nbf": 1790110888,
"sub": "urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2",
"aud": "https://127.0.0.1:38081/resource",
"iss": "https://127.0.0.1:38081",
"jti": "QAleLVpphyI22Ah96I60nw"
}
}
UserInfo response as a JWT
Plain JSON unless the client registered userinfo_signed_response_alg (or
an encryption algorithm), in which case GET /oauth2/userinfo answers
application/jwt. The payload’s typ is UserInfo, and aud is the
client. Registered with {"redirect_uris":[…],"userinfo_signed_response_alg":"RS256"}
at /oauth2/register, token from the password grant with
scope=openid profile email:
Encoded (shortened):
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InN0cy1mNzA0NTI0…qPuyg_prtkE3Ja_WiK9g
Header:
{
"alg": "RS256",
"typ": "JWT",
"kid": "sts-f7045241e6b0",
"x5u": "https://127.0.0.1:38081/pki/chain/default/8f1e19cfeec3d56c499825b1ef7094961166198463b14e301914bef595c199dc.pem"
}
Payload:
{
"iss": "https://127.0.0.1:38081",
"aud": "sts-client-eoo6k70Q_BM",
"typ": "UserInfo",
"groups": [
"developers"
],
"name": "alice (mock)",
"given_name": "alice",
"family_name": "Mock",
"preferred_username": "alice",
"email": "alice@example.com",
"email_verified": true,
"sub": "urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2",
"iat": 1790111229
}
Back-channel Logout Token
OpenID Connect Back-Channel Logout 1.0.
It is POSTed as logout_token=… to every relying party with a
backchannel_logout_uri on a session that a sign-out, an expiry or a disable
ends. typ is logout+jwt. It has an events member, and no nonce, so it
cannot pass as an ID Token. This one went to a client registered with
backchannel_logout_uri and backchannel_logout_session_required, after a
POST /logout.
Encoded (shortened):
eyJhbGciOiJSUzI1NiIsInR5cCI6ImxvZ291dCtqd3QiLCJraWQiOiJzdHMt…ccHV_s7joyrUJCx-78QA
Header:
{
"alg": "RS256",
"typ": "logout+jwt",
"kid": "sts-f7045241e6b0",
"x5u": "https://127.0.0.1:38081/pki/chain/default/8f1e19cfeec3d56c499825b1ef7094961166198463b14e301914bef595c199dc.pem"
}
Payload:
{
"iss": "https://127.0.0.1:38081",
"aud": "sts-client-uKVxpMdQRw8",
"iat": 1790110868,
"exp": 1790110988,
"jti": "5PQLkv9b02A7d-Za-L_Usw",
"events": {
"http://schemas.openid.net/event/backchannel-logout": {}
},
"sub": "urn:uuid:3cea6a34-920a-5d76-a92f-8c48e3c242e2",
"sid": "O6TQEO65_DvzQwagWzON9_fDYxLrqFhq"
}
WS-Trust JWT
WS-Trust issues a JWT when the RequestSecurityToken asks for
TokenType urn:ietf:params:oauth:token-type:jwt. It comes back as a
wsse:BinarySecurityToken; the whole response is under
WS-Trust, below. Its issuer is
wstrust.issuer, not the OAuth issuer.
Encoded (shortened):
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InN0cy1mNzA0NTI0…pOEKlLtol60lc225EQkQ
Header:
{
"alg": "RS256",
"typ": "JWT",
"kid": "sts-f7045241e6b0",
"x5u": "https://127.0.0.1:38081/pki/chain/default/8f1e19cfeec3d56c499825b1ef7094961166198463b14e301914bef595c199dc.pem"
}
Payload:
{
"iss": "urn:wstrust:mock:sts",
"sub": "urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2",
"name": "alice",
"iat": 1790110586,
"exp": 1790114186,
"jti": "NMoXwR8cHHDGDpd62DzFQFxy",
"aud": "https://rp.example.org/"
}
The status list tokens, the OpenID4VP request object, the Domain Linkage Credential and the JWT-SVID are JWTs as well. They are under Verifiable credentials and SPIFFE SVIDs.
Software statement (RFC 7591 section 2.3)
From the second start of the service (see the note at the top), so its keys differ from the samples above.
An administrator issues a signed statement of a publisher’s
client metadata. A client then presents it as software_statement at
/oauth2/register, and the values it fixes win over the ones sent beside it.
typ is software-statement+jwt.
curl -X POST https://127.0.0.1:38081/admin-api/applications/issue-software-statement \
-H "Authorization: Bearer $ADMIN_TOKEN" -H 'content-type: application/json' \
-d '{"application":"<publisher client_id>","metadata":{"software_id":"acme-mobile-app",
"software_version":"4.2","client_name":"Acme Mobile",
"redirect_uris":["com.acme.mobile:/oauth2/cb"],
"grant_types":["authorization_code","refresh_token"],
"token_endpoint_auth_method":"none"}}'
Encoded (shortened):
eyJhbGciOiJSUzI1NiIsInR5cCI6InNvZnR3YXJlLXN0YXRlbWVudCtqd3Qi…VIbAU6zkCrSBFyvFz-5w
Header:
{
"alg": "RS256",
"typ": "software-statement+jwt",
"kid": "sts-8525a218fafe"
}
Payload:
{
"software_id": "acme-mobile-app",
"software_version": "4.2",
"client_name": "Acme Mobile",
"redirect_uris": [
"com.acme.mobile:/oauth2/cb"
],
"grant_types": [
"authorization_code",
"refresh_token"
],
"token_endpoint_auth_method": "none",
"iss": "https://127.0.0.1:38081",
"sub": "sts-client-Xiok04NIR48",
"iat": 1790111793,
"jti": "7znJ6CQwgLwkVx5K_gGZ1g",
"exp": 1821647793
}
Signed discovery metadata (signed_metadata)
From the second start of the service (see the note at the top), so its keys differ from the samples above.
GET /.well-known/openid-configuration (and
/.well-known/oauth-authorization-server) carries every member as plain
JSON and again as signed_metadata, a JWT signed with the realm key
(RFC 8414 section 2.1).
When the two differ, a client that verified the JWT uses the signed values.
The payload is the whole document, so only a few members are shown here.
The OpenID4VCI issuer metadata carries a signed_metadata of the same kind.
Encoded (shortened):
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InN0cy04NTI1YTIx…RsX5Rtv8zrBdv2D3c5Zg
Header:
{
"alg": "RS256",
"typ": "JWT",
"kid": "sts-8525a218fafe",
"x5u": "https://127.0.0.1:38081/pki/chain/default/06e0368d006718352a8b5d103d29a41095e3e0a4fa2f53f912f8fccfdfa91402.pem"
}
Payload (66 members; 8 shown):
{
"issuer": "https://127.0.0.1:38081",
"authorization_endpoint": "https://127.0.0.1:38081/oauth2/authorize",
"token_endpoint": "https://127.0.0.1:38081/oauth2/token",
"jwks_uri": "https://127.0.0.1:38081/oauth2/jwks",
"registration_endpoint": "https://127.0.0.1:38081/oauth2/register",
"iat": 1790111766,
"exp": 1790115366,
"iss": "https://127.0.0.1:38081"
}
Crypto metadata (/crypto/metadata.jwt)
From the second start of the service (see the note at the top), so its keys differ from the samples above.
This service’s own document of every signing key it holds, per realm. Each unit is a use (JOSE signing per algorithm, XML signing, SPIFFE, …) with each key generation and its certificate chain. It is published as JSON, XML, a JWT signed with the realm key, and XML with an enveloped signature. The JWT is about 200 KB; one unit is shown here, with its long values shortened.
Header:
{
"alg": "RS256",
"typ": "JWT",
"kid": "sts-8525a218fafe",
"x5u": "https://127.0.0.1:38081/pki/chain/default/06e0368d006718352a8b5d103d29a41095e3e0a4fa2f53f912f8fccfdfa91402.pem"
}
Payload (shortened):
{
"specVersion": 1,
"issuer": "https://127.0.0.1:38081",
"realm": "default",
"generatedAt": "2026-09-22T21:16:06.937Z",
"rotation": {
"scheduled": false,
"intervalDays": 90,
"retiredKeyGraceDays": 0,
"why": "this is a development-mode service, whose keys are made anew at every start and are not rotated"
},
"units": [
{
"unit": "jose:RS256",
"useCase": "jose",
"alg": "RS256",
"crv": null,
"kind": "rsa",
"purposes": [
"access_token",
"id_token",
"refresh_token",
"logout_token",
"userinfo_response",
"introspection_response",
"signed_metadata",
"software_statement",
"security_event",
"credential",
"status_list",
"request_object"
],
"lastRotated": null,
"keys": [
{
"kid": "sts-8525a218fafe",
"state": "current",
"jwk": {
"kty": "RSA",
"n": "uvKrGJmKlGJI8N7UzIVKD1UVbuw3NbcEn1WcJLmq…",
"e": "AQAB",
"kid": "sts-8525a218fafe",
"use": "sig"
},
"certificate": {
"x5c": [
"MIIEdDCCA16gAwIBAgIQUQ9nOdaSZAtOWjYVehkR…",
"… 2 more"
],
"subject": "CN=JOSE signing (RS256), O=sts",
"issuer": "CN=sts JOSE Signing CA (default), O=sts",
"serialNumber": "510F6739D692640B4E5A36157A191114",
"notBefore": "2026-09-22T21:12:06.000Z",
"notAfter": "2027-09-22T21:12:06.000Z",
"sha256Fingerprint": "06e0368d006718352a8b5d103d29a41095e3e0a4fa2f53f912f8fccfdfa91402",
"selfSigned": false,
"crl": [
"http://localhost:8082/pki/crl/default/jose.crl",
"ldap://localhost:389/cn=jose,ou=crl,dc=e…"
],
"ocsp": "http://localhost:8082/pki/ocsp/default/jose",
"caIssuers": "http://localhost:8082/pki/ca/default/jose.cer"
}
}
]
},
"… 18 more signing units"
],
"algorithms": {
"jose": {
"signing": [
"RS256",
"RS384",
"RS512",
"PS256",
"… 18 more"
],
"default": "RS256",
"signedMetadata": "RS256",
"encryption": {
"alg": [
"RSA-OAEP-256",
"RSA-OAEP",
"ECDH-ES",
"ECDH-ES+A128KW",
"ECDH-ES+A192KW",
"ECDH-ES+A256KW",
"A128KW",
"A192KW",
"A256KW",
"A128GCMKW",
"A192GCMKW",
"A256GCMKW",
"PBES2-HS256+A128KW",
"PBES2-HS384+A192KW",
"PBES2-HS512+A256KW",
"dir"
],
"enc": [
"A128GCM",
"A192GCM",
"A256GCM",
"A128CBC-HS256",
"A192CBC-HS384",
"A256CBC-HS512"
]
}
},
"xml": {
"signing": [
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha224",
"http://www.w3.org/2007/05/xmldsig-more#rsa-sha224",
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
"… 36 more"
],
"default": "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
}
},
"links": {
"jwks_uri": "https://127.0.0.1:38081/oauth2/jwks",
"openid_configuration": "https://127.0.0.1:38081/.well-known/openid-configuration",
"saml2_metadata": "https://127.0.0.1:38081/saml2/metadata",
"wsfed_metadata": "https://127.0.0.1:38081/FederationMetadata/2007-06/FederationMetadata.xml",
"json": "https://127.0.0.1:38081/crypto/metadata.json",
"xml": "https://127.0.0.1:38081/crypto/metadata.xml",
"signed_json": "https://127.0.0.1:38081/crypto/metadata.jwt",
"signed_xml": "https://127.0.0.1:38081/crypto/metadata.signed.xml",
"schema": "https://127.0.0.1:38081/crypto/metadata.xsd"
},
"sub": "https://127.0.0.1:38081",
"iat": 1790111766,
"exp": 1790115366,
"iss": "https://127.0.0.1:38081"
}
SAML 2.0 assertion
A Web Browser SSO Response over the HTTP-POST binding, answering an
unsigned AuthnRequest from https://sp.example.org, which development mode
serves without registration. The request was sent over the HTTP-Redirect
binding:
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_docs1" Version="2.0"
IssueInstant="…" Destination="https://127.0.0.1:38081/saml2/sso"
AssertionConsumerServiceURL="https://sp.example.org/saml/acs"
ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST">
<saml:Issuer>https://sp.example.org</saml:Issuer>
</samlp:AuthnRequest>
The response is the base64 SAMLResponse field of the auto-posting form.
Both the Response and the Assertion are signed (RSA-SHA256, exclusive
C14N). The KeyInfo certificate is issued by the realm’s XML signing CA.
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_2114a1cac6ec1cd39be48fe07f4e79e8" Version="2.0" IssueInstant="2026-09-22T20:55:15.421Z" Destination="https://sp.example.org/saml/acs" InResponseTo="_docs1">
<saml:Issuer>urn:sts:idp:app-aaf6073df227</saml:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#_2114a1cac6ec1cd39be48fe07f4e79e8">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>Jx7BjK6Qhm1icmXBod2sPRj4…</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>T5XUiqmpn//Z3ob0j+ycklUK…</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIEbjCCA1igAwIBAgIQN+qz…</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_1005fb4d063d2743146fe26e759c3f7f" Version="2.0" IssueInstant="2026-09-22T20:55:15.389Z">
<saml:Issuer>urn:sts:idp:app-aaf6073df227</saml:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#_1005fb4d063d2743146fe26e759c3f7f">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>MD48zmHiaCpDZYVpoYQA+rsO…</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>Qo+L6c3i1ArA24fKyMBYIqhe…</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIEbjCCA1igAwIBAgIQN+qz…</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">alice</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData NotOnOrAfter="2026-09-22T21:55:15.388Z" Recipient="https://sp.example.org/saml/acs" InResponseTo="_docs1"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2026-09-22T20:55:15.389Z" NotOnOrAfter="2026-09-22T21:55:15.389Z">
<saml:AudienceRestriction>
<saml:Audience>https://sp.example.org</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2026-09-22T20:54:36.000Z" SessionIndex="sHiKmHBkOJ6bjKXM-TnFoHzZPEPIzHS7">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml:AttributeValue>Mock</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml:AttributeValue>alice@example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml:AttributeValue>urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue>alice@example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="givenName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="sn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue>Mock</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="displayName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue>alice (mock)</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="urn:oid:0.9.2342.19200300.100.1.1" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="uid">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="urn:oid:0.9.2342.19200300.100.1.3" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="mail">
<saml:AttributeValue>alice@example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="givenName">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="urn:oid:2.5.4.4" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="sn">
<saml:AttributeValue>Mock</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="urn:oid:2.16.840.1.113730.3.1.241" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="displayName">
<saml:AttributeValue>alice (mock)</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="groups">
<saml:AttributeValue>developers</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>
- The
Issuerisurn:sts:idp:app-…, a per-application entityID (saml2.perApplicationEntityId). SessionIndexis the session’ssid, the value in the ID Token.NameIDis the user name in theunspecifiedformat by default. ANameIDPolicyorsaml2.nameIdFormatpicks another format; see SAML 2.0 Web Browser SSO.
SAML 2.0 artifact
The same request with ProtocolBinding set to the HTTP-Artifact binding
sends the browser back with a SAMLart instead of the response:
https://sp.example.org/saml/acs?SAMLart=AAQAAEsd2WlW%2BnW3m3q9nHN8CjaKwK8UyoXV8nBHbKGykNSjAAb3M7iWzg0%3D
Decoded, it is the 44 bytes of SAML 2.0 Bindings section 3.6.4:
| Bytes | Value | Meaning |
|---|---|---|
| 0–1 | 0004 |
TypeCode 4 |
| 2–3 | 0000 |
EndpointIndex of the artifact resolution service |
| 4–23 | 4b1dd96956fa75b79b7abd9c737c0a368ac0af14 |
SourceID: SHA-1 of the entityID urn:sts:idp:app-aaf6073df227 |
| 24–43 | ca85d5f270476ca1b290d4a30006f733b896ce0d |
MessageHandle: random, one use |
The service provider exchanges it with a SOAP ArtifactResolve at
POST /saml2/ars and receives a signed ArtifactResponse wrapping the
Response shown above. Resolving an artifact destroys it, so a second
resolve gets nothing.
SAML 2.0 ArtifactResponse
From the second start of the service (see the note at the top), so its keys differ from the samples above.
The service provider resolves the artifact over the SOAP
binding at the resolver its metadata names, POST /saml2/ars/{sp}:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body>
<samlp:ArtifactResolve xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_docsres2" Version="2.0"
IssueInstant="…" Destination="https://127.0.0.1:38081/saml2/ars/app-aaf6073df227">
<saml:Issuer>https://sp.example.org</saml:Issuer>
<samlp:Artifact>AAQAAEsd2WlW+nW3m3q9nHN8CjaKwK8UHnFtwio5G+yW3v04/DVHF7U/zgI=</samlp:Artifact>
</samlp:ArtifactResolve>
</soap:Body></soap:Envelope>
The ArtifactResponse itself is unsigned on purpose: what the service
provider verifies is the signed Response inside it, and the back channel
is protected by TLS. The inner signatures are shortened to one line.
Resolving the same artifact at the unscoped /saml2/ars also works, and
answers with a different Issuer. That is a bug,
#160.
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<samlp:ArtifactResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_5747603c71e8bb2bec676132012de9e2" Version="2.0" IssueInstant="2026-09-22T21:14:19.493Z" InResponseTo="_docsres2">
<saml:Issuer>urn:sts:idp:app-aaf6073df227</saml:Issuer>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_c730984c573bb5dc9bcb17c5b7779bf1" Version="2.0" IssueInstant="2026-09-22T21:14:19.303Z" Destination="https://sp.example.org/saml/acs" InResponseTo="_docs4">
<saml:Issuer>urn:sts:idp:app-aaf6073df227</saml:Issuer>
<ds:Signature>…enveloped signature, as in the SAML 2.0 sample…</ds:Signature>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
</samlp:Status>
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_4fac291f0a1b510f377062fa43971ac3" Version="2.0" IssueInstant="2026-09-22T21:14:19.230Z">
<saml:Issuer>urn:sts:idp:app-aaf6073df227</saml:Issuer>
<ds:Signature>…enveloped signature, as in the SAML 2.0 sample…</ds:Signature>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">alice</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData NotOnOrAfter="2026-09-22T22:14:19.229Z" Recipient="https://sp.example.org/saml/acs" InResponseTo="_docs4"/>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2026-09-22T21:14:19.230Z" NotOnOrAfter="2026-09-22T22:14:19.230Z">
<saml:AudienceRestriction>
<saml:Audience>https://sp.example.org</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2026-09-22T21:13:14.000Z" SessionIndex="16g7q765xwycim_M3yhkyzpjDFSrlzFx">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml:AttributeValue>Mock</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml:AttributeValue>alice@example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml:AttributeValue>urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="uid" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="mail" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue>alice@example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="givenName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="sn" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue>Mock</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="displayName" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
<saml:AttributeValue>alice (mock)</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="urn:oid:0.9.2342.19200300.100.1.1" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="uid">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="urn:oid:0.9.2342.19200300.100.1.3" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="mail">
<saml:AttributeValue>alice@example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="urn:oid:2.5.4.42" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="givenName">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="urn:oid:2.5.4.4" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="sn">
<saml:AttributeValue>Mock</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="urn:oid:2.16.840.1.113730.3.1.241" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="displayName">
<saml:AttributeValue>alice (mock)</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="groups">
<saml:AttributeValue>developers</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</samlp:Response>
</samlp:ArtifactResponse>
</soap:Body>
</soap:Envelope>
SAML 2.0 identity provider metadata
From the second start of the service (see the note at the top), so its keys differ from the samples above.
GET /saml2/metadata/{sp}: the per-application
EntityDescriptor, signed (the signature comes first, as the metadata
schema requires). GET /saml2/metadata is the service-wide one
(urn:sts:idp). The WS-Federation equivalent is at
/FederationMetadata/2007-06/FederationMetadata.xml, and SAML 1.1’s is at
/saml11/metadata.
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" ID="_912703adb9b5af5facf10294115ac77e" entityID="urn:sts:idp:app-aaf6073df227">
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference URI="#_912703adb9b5af5facf10294115ac77e">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>CCvPLvOLH0Rpr9GVhJuirUdl…</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>ezB/v041j6Jpm8qbyOVCIjZb…</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>MIIEbjCCA1igAwIBAgIQMztF…</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<md:Extensions>
<cm:CryptoMetadataLocation xmlns:cm="urn:iya:sts:crypto-metadata:1">https://127.0.0.1:38081/crypto/metadata.xml</cm:CryptoMetadataLocation>
</md:Extensions>
<md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIIEbjCCA1igAwIBAgIQMztF…</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:KeyDescriptor use="encryption">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIIEbjCCA1igAwIBAgIQMztF…</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:ArtifactResolutionService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://127.0.0.1:38081/saml2/ars/app-aaf6073df227" index="0" isDefault="true"/>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://127.0.0.1:38081/saml2/slo/app-aaf6073df227"/>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://127.0.0.1:38081/saml2/slo/app-aaf6073df227"/>
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" Location="https://127.0.0.1:38081/saml2/slo/app-aaf6073df227"/>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:entity</md:NameIDFormat>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://127.0.0.1:38081/saml2/sso/app-aaf6073df227"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://127.0.0.1:38081/saml2/sso/app-aaf6073df227"/>
<md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign" Location="https://127.0.0.1:38081/saml2/sso/app-aaf6073df227"/>
</md:IDPSSODescriptor>
<md:AttributeAuthorityDescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>MIIEbjCCA1igAwIBAgIQMztF…</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:AttributeService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="https://127.0.0.1:38081/saml2/aa/app-aaf6073df227"/>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:transient</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:X509SubjectName</md:NameIDFormat>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:entity</md:NameIDFormat>
</md:AttributeAuthorityDescriptor>
<md:Organization>
<md:OrganizationName xml:lang="en">sts</md:OrganizationName>
<md:OrganizationDisplayName xml:lang="en">Mock security token service</md:OrganizationDisplayName>
<md:OrganizationURL xml:lang="en">https://127.0.0.1:38081/</md:OrganizationURL>
</md:Organization>
</md:EntityDescriptor>
SAML 1.1 assertion
The SAML 1.1 Browser/POST profile, started at the inter-site transfer service with Shibboleth’s request parameters:
GET https://127.0.0.1:38081/saml11/sso?TARGET=https://sp11.example.org/app&shire=https://sp11.example.org/saml11/acs&providerId=https://sp11.example.org
SAML 1.1 puts the Issuer on the assertion as an attribute. The subject
appears once per statement. Attributes are named by AttributeName and
AttributeNamespace rather than a URI. The two signatures are the same shape
as SAML 2.0’s, so they are shortened to one line here.
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" ResponseID="_2e010a46f60a0dd5a4111e29c784d800" MajorVersion="1" MinorVersion="1" IssueInstant="2026-09-22T20:55:22.196Z" Recipient="https://sp11.example.org/saml11/acs">
<ds:Signature>…enveloped signature, as in the SAML 2.0 sample…</ds:Signature>
<samlp:Status>
<samlp:StatusCode Value="samlp:Success"/>
</samlp:Status>
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" MajorVersion="1" MinorVersion="1" AssertionID="_b481af8c611fa47bc18bfce50b154976" Issuer="urn:sts:idp:saml11:app-2b946c3616bd" IssueInstant="2026-09-22T20:55:22.167Z">
<saml:Conditions NotBefore="2026-09-22T20:55:22.167Z" NotOnOrAfter="2026-09-22T21:55:22.167Z">
<saml:AudienceRestrictionCondition>
<saml:Audience>https://sp11.example.org</saml:Audience>
</saml:AudienceRestrictionCondition>
<saml:DoNotCacheCondition/>
</saml:Conditions>
<saml:AuthenticationStatement AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:password" AuthenticationInstant="2026-09-22T20:54:36.000Z">
<saml:Subject>
<saml:NameIdentifier NameQualifier="urn:sts:idp:saml11:app-2b946c3616bd" Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">alice</saml:NameIdentifier>
<saml:SubjectConfirmation>
<saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:SubjectLocality IPAddress="172.17.0.1"/>
</saml:AuthenticationStatement>
<saml:AttributeStatement>
<saml:Subject>
<saml:NameIdentifier NameQualifier="urn:sts:idp:saml11:app-2b946c3616bd" Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">alice</saml:NameIdentifier>
<saml:SubjectConfirmation>
<saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Attribute AttributeName="name" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="givenname" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="surname" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>Mock</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="emailaddress" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>alice@example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="nameidentifier" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="upn" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>alice@example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="authenticationmethod" AttributeNamespace="http://schemas.microsoft.com/ws/2008/06/identity/claims">
<saml:AttributeValue>urn:oasis:names:tc:SAML:1.0:am:password</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="authenticationinstant" AttributeNamespace="http://schemas.microsoft.com/ws/2008/06/identity/claims">
<saml:AttributeValue>2026-09-22T20:54:36.000Z</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="urn:mace:dir:attribute-def:uid" AttributeNamespace="urn:mace:shibboleth:1.0:attributeNamespace:uri">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="urn:mace:dir:attribute-def:mail" AttributeNamespace="urn:mace:shibboleth:1.0:attributeNamespace:uri">
<saml:AttributeValue>alice@example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="urn:mace:dir:attribute-def:givenName" AttributeNamespace="urn:mace:shibboleth:1.0:attributeNamespace:uri">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="urn:mace:dir:attribute-def:sn" AttributeNamespace="urn:mace:shibboleth:1.0:attributeNamespace:uri">
<saml:AttributeValue>Mock</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="urn:mace:dir:attribute-def:displayName" AttributeNamespace="urn:mace:shibboleth:1.0:attributeNamespace:uri">
<saml:AttributeValue>alice (mock)</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="groups" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>developers</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
<ds:Signature>…enveloped signature, as in the SAML 2.0 sample…</ds:Signature>
</saml:Assertion>
</samlp:Response>
SAML 1.1 artifact
From the second start of the service (see the note at the top), so its keys differ from the samples above.
The non-standard profile=artifact parameter on
/saml11/sso selects Browser/Artifact. The browser comes back to the
shire with SAMLart and TARGET:
https://sp11.example.org/saml11/acs?SAMLart=AAHNn0I4HwELxDxT1HpT8xKvnqiFCvT+rOVvV7fnvs29s7DYFfaG2eht&TARGET=https://sp11.example.org/app
A SAML 1.1 type 0x0001 artifact is 42 bytes:
| Bytes | Value | Meaning |
|---|---|---|
| 0–1 | 0001 |
TypeCode 1 |
| 2–21 | cd9f42381f010bc43c53d47a53f312af9ea8850a |
SourceID: SHA-1 of the providerID urn:sts:idp:saml11:app-2b946c3616bd |
| 22–41 | f4feace56f57b7e7becdbdb3b0d815f686d9e86d |
AssertionHandle: random, one use |
The relying party resolves it with a SOAP samlp:Request at
POST /saml11/responder:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body>
<samlp:Request xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" MajorVersion="1"
MinorVersion="1" RequestID="_docsreq1" IssueInstant="…">
<samlp:AssertionArtifact>AAHNn0I4HwELxDxT1HpT8xKvnqiFCvT+rOVvV7fnvs29s7DYFfaG2eht</samlp:AssertionArtifact>
</samlp:Request>
</soap:Body></soap:Envelope>
The answer is a signed samlp:Response whose assertion is built when it is
resolved. Its subject confirmation is cm:artifact, not cm:bearer:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:1.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" ResponseID="_b13e05e3715e09ec927a61d1be712bd3" MajorVersion="1" MinorVersion="1" IssueInstant="2026-09-22T21:13:23.222Z" Recipient="https://sp11.example.org" InResponseTo="_docsreq1">
<ds:Signature>…enveloped signature, as in the SAML 2.0 sample…</ds:Signature>
<samlp:Status>
<samlp:StatusCode Value="samlp:Success"/>
</samlp:Status>
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" MajorVersion="1" MinorVersion="1" AssertionID="_70bb85d350e7c93f40e7174d5553b687" Issuer="urn:sts:idp:saml11:app-2b946c3616bd" IssueInstant="2026-09-22T21:13:14.852Z">
<saml:Conditions NotBefore="2026-09-22T21:13:14.852Z" NotOnOrAfter="2026-09-22T22:13:14.852Z">
<saml:AudienceRestrictionCondition>
<saml:Audience>https://sp11.example.org</saml:Audience>
</saml:AudienceRestrictionCondition>
</saml:Conditions>
<saml:AuthenticationStatement AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:password" AuthenticationInstant="2026-09-22T21:13:14.000Z">
<saml:Subject>
<saml:NameIdentifier NameQualifier="urn:sts:idp:saml11:app-2b946c3616bd" Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">alice</saml:NameIdentifier>
<saml:SubjectConfirmation>
<saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:artifact</saml:ConfirmationMethod>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:SubjectLocality IPAddress="172.17.0.1"/>
</saml:AuthenticationStatement>
<saml:AttributeStatement>
<saml:Subject>
<saml:NameIdentifier NameQualifier="urn:sts:idp:saml11:app-2b946c3616bd" Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">alice</saml:NameIdentifier>
<saml:SubjectConfirmation>
<saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:artifact</saml:ConfirmationMethod>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Attribute AttributeName="name" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="givenname" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="surname" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>Mock</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="emailaddress" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>alice@example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="nameidentifier" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="upn" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>alice@example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="authenticationmethod" AttributeNamespace="http://schemas.microsoft.com/ws/2008/06/identity/claims">
<saml:AttributeValue>urn:oasis:names:tc:SAML:1.0:am:password</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="authenticationinstant" AttributeNamespace="http://schemas.microsoft.com/ws/2008/06/identity/claims">
<saml:AttributeValue>2026-09-22T21:13:14.000Z</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="urn:mace:dir:attribute-def:uid" AttributeNamespace="urn:mace:shibboleth:1.0:attributeNamespace:uri">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="urn:mace:dir:attribute-def:mail" AttributeNamespace="urn:mace:shibboleth:1.0:attributeNamespace:uri">
<saml:AttributeValue>alice@example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="urn:mace:dir:attribute-def:givenName" AttributeNamespace="urn:mace:shibboleth:1.0:attributeNamespace:uri">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="urn:mace:dir:attribute-def:sn" AttributeNamespace="urn:mace:shibboleth:1.0:attributeNamespace:uri">
<saml:AttributeValue>Mock</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="urn:mace:dir:attribute-def:displayName" AttributeNamespace="urn:mace:shibboleth:1.0:attributeNamespace:uri">
<saml:AttributeValue>alice (mock)</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="groups" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>developers</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
<ds:Signature>…enveloped signature, as in the SAML 2.0 sample…</ds:Signature>
</saml:Assertion>
</samlp:Response>
</soap:Body>
</soap:Envelope>
WS-Federation and WS-Trust responses
WS-Federation sign-in response
The passive requestor profile answers wa=wsignin1.0 with a form that posts
wresult, a RequestSecurityTokenResponse carrying a signed SAML 1.1
assertion (the same builder as SAML 1.1):
GET https://127.0.0.1:38081/wsfed?wa=wsignin1.0&wtrealm=urn:rp:docs&wreply=https://rp.example.org/wsfed&wctx=docs
<t:RequestSecurityTokenResponse xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
<t:Lifetime>
<wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2026-09-22T20:55:28.975Z</wsu:Created>
<wsu:Expires xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">2026-09-22T21:55:28.975Z</wsu:Expires>
</t:Lifetime>
<wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy">
<wsa:EndpointReference xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:Address>urn:rp:docs</wsa:Address>
</wsa:EndpointReference>
</wsp:AppliesTo>
<t:RequestedSecurityToken>
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:1.0:assertion" MajorVersion="1" MinorVersion="1" AssertionID="_97cbca81dcb4d15fc59d635bb9ae5cb9" Issuer="urn:wstrust:mock:sts" IssueInstant="2026-09-22T20:55:28.946Z">
<saml:Conditions NotBefore="2026-09-22T20:55:28.946Z" NotOnOrAfter="2026-09-22T21:55:28.946Z">
<saml:AudienceRestrictionCondition>
<saml:Audience>urn:rp:docs</saml:Audience>
</saml:AudienceRestrictionCondition>
</saml:Conditions>
<saml:AuthenticationStatement AuthenticationMethod="urn:oasis:names:tc:SAML:1.0:am:password" AuthenticationInstant="2026-09-22T20:54:36.000Z">
<saml:Subject>
<saml:NameIdentifier Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">alice</saml:NameIdentifier>
<saml:SubjectConfirmation>
<saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod>
</saml:SubjectConfirmation>
</saml:Subject>
</saml:AuthenticationStatement>
<saml:AttributeStatement>
<saml:Subject>
<saml:NameIdentifier Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">alice</saml:NameIdentifier>
<saml:SubjectConfirmation>
<saml:ConfirmationMethod>urn:oasis:names:tc:SAML:1.0:cm:bearer</saml:ConfirmationMethod>
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Attribute AttributeName="nameidentifier" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="name" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="givenname" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="surname" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>Mock</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="emailaddress" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>alice@example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="upn" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>alice@example.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="authenticationmethod" AttributeNamespace="http://schemas.microsoft.com/ws/2008/06/identity/claims">
<saml:AttributeValue>urn:oasis:names:tc:SAML:1.0:am:password</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="authenticationinstant" AttributeNamespace="http://schemas.microsoft.com/ws/2008/06/identity/claims">
<saml:AttributeValue>2026-09-22T20:54:36.000Z</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute AttributeName="groups" AttributeNamespace="http://schemas.xmlsoap.org/ws/2005/05/identity/claims">
<saml:AttributeValue>developers</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
<ds:Signature>…enveloped signature, as in the SAML 2.0 sample…</ds:Signature>
</saml:Assertion>
</t:RequestedSecurityToken>
<t:TokenType>urn:oasis:names:tc:SAML:1.0:assertion</t:TokenType>
<t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
<t:KeyType>http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey</t:KeyType>
</t:RequestSecurityTokenResponse>
WS-Trust RSTR carrying a SAML 2.0 assertion
A WS-Trust 1.3 Issue over SOAP 1.2 with a UsernameToken. With no
TokenType, the token is a signed SAML 2.0 assertion from the SAML 2.0
identity provider’s builder:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512"
xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
xmlns:wsa="http://www.w3.org/2005/08/addressing">
<s:Header><wsse:Security><wsse:UsernameToken>
<wsse:Username>alice</wsse:Username><wsse:Password>x</wsse:Password>
</wsse:UsernameToken></wsse:Security></s:Header>
<s:Body><wst:RequestSecurityToken>
<wst:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</wst:RequestType>
<wsp:AppliesTo><wsa:EndpointReference>
<wsa:Address>https://rp.example.org/</wsa:Address>
</wsa:EndpointReference></wsp:AppliesTo>
</wst:RequestSecurityToken></s:Body>
</s:Envelope>
POSTed to /sts, answered:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal</wsa:Action>
</soap:Header>
<soap:Body>
<wst:RequestSecurityTokenResponseCollection xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
<wst:RequestSecurityTokenResponse>
<wst:TokenType>http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV2.0</wst:TokenType>
<wst:RequestedSecurityToken>
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_516945cce8286656b15e95873ea73743" Version="2.0" IssueInstant="2026-09-22T20:56:26.019Z">
<saml:Issuer>urn:wstrust:mock:sts</saml:Issuer>
<ds:Signature>…enveloped signature, as in the SAML 2.0 sample…</ds:Signature>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">alice</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"/>
</saml:Subject>
<saml:Conditions NotBefore="2026-09-22T20:56:26.019Z" NotOnOrAfter="2026-09-22T21:56:26.019Z">
<saml:AudienceRestriction>
<saml:Audience>https://rp.example.org/</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2026-09-22T20:56:26.019Z" SessionIndex="_516945cce8286656b15e95873ea73743">
<saml:AuthnContext>
<saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute Name="name">
<saml:AttributeValue>alice</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="issuedBy">
<saml:AttributeValue>urn:wstrust:mock:sts</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="groups">
<saml:AttributeValue>developers</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
</wst:RequestedSecurityToken>
<wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:EndpointReference>
<wsa:Address>https://rp.example.org/</wsa:Address>
</wsa:EndpointReference>
</wsp:AppliesTo>
<wst:Lifetime xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsu:Created>2026-09-22T20:56:26.058Z</wsu:Created>
<wsu:Expires>2026-09-22T21:56:26.058Z</wsu:Expires>
</wst:Lifetime>
<wst:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</wst:KeyType>
<wst:RequestedAttachedReference>
<wsse:SecurityTokenReference xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLID">_516945cce8286656b15e95873ea73743</wsse:KeyIdentifier>
</wsse:SecurityTokenReference>
</wst:RequestedAttachedReference>
</wst:RequestSecurityTokenResponse>
</wst:RequestSecurityTokenResponseCollection>
</soap:Body>
</soap:Envelope>
WS-Trust RSTR carrying a JWT
The same request with
<wst:TokenType>urn:ietf:params:oauth:token-type:jwt</wst:TokenType>. The
JWT is decoded under Other JWTs.
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<wsa:Action xmlns:wsa="http://www.w3.org/2005/08/addressing">http://docs.oasis-open.org/ws-sx/ws-trust/200512/RSTRC/IssueFinal</wsa:Action>
</soap:Header>
<soap:Body>
<wst:RequestSecurityTokenResponseCollection xmlns:wst="http://docs.oasis-open.org/ws-sx/ws-trust/200512">
<wst:RequestSecurityTokenResponse>
<wst:TokenType>urn:ietf:params:oauth:token-type:jwt</wst:TokenType>
<wst:RequestedSecurityToken>
<wsse:BinarySecurityToken xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" ValueType="urn:ietf:params:oauth:token-type:jwt">eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InN0cy1mNzA0NTI0MWU2YjAiLCJ4NXUiOiJodHRwczovLzEyNy4wLjAuMTozODA4MS9wa2kvY2hhaW4vZGVmYXVsdC84ZjFlMTljZmVlYzNkNTZjNDk5ODI1YjFlZjcwOTQ5NjExNjYxOTg0NjNiMTRlMzAxOTE0YmVmNTk1YzE5OWRjLnBlbSJ9.eyJpc3MiOiJ1cm46d3N0cnVzdDptb2NrOnN0cyIsInN1YiI6InVybjp1dWlkOjAxNmRjOGYxLTFiYzQtNTVkOS05NjU3LTliMmViYjNjZDRkMiIsIm5hbWUiOiJhbGljZSIsImlhdCI6MTc5MDExMDU4NiwiZXhwIjoxNzkwMTE0MTg2LCJqdGkiOiJOTW9Yd1I4Y0hIREdEcGQ2MkR6RlFGeHkiLCJhdWQiOiJodHRwczovL3JwLmV4YW1wbGUub3JnLyJ9.aYT6_coGff_o0wyWwCVBDEnGX3Jwdeh5GgrkigIOTsEZ-WOMvbkOk--emI4g6DTHhE4RLOq5l3ikvOLv4xoCIQQrubEQkPYNVFQlT_BAOUSaH2o79UhcU2T5-rminWuuUcl8H7eZqCoxfXs55hwV3kzkvpJuQ6Vm0SJCWPgZ3Ujvgu5ZvYGzknZMHLImOApwAraZ1N2l0IJF1eIIv0muykMbJPU_tg9szynaiVd1fWFTseYrX518C8svsQ_3p8iTSIgmGYEdwCf7G_pkG-UQwL2M0HYrJXwBZ2uUyGgL_nzTgxOjzxq_ph4kN0FuP2Da6JpOEKlLtol60lc225EQkQ</wsse:BinarySecurityToken>
</wst:RequestedSecurityToken>
<wsp:AppliesTo xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsa:EndpointReference>
<wsa:Address>https://rp.example.org/</wsa:Address>
</wsa:EndpointReference>
</wsp:AppliesTo>
<wst:Lifetime xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsu:Created>2026-09-22T20:56:26.089Z</wsu:Created>
<wsu:Expires>2026-09-22T21:56:26.090Z</wsu:Expires>
</wst:Lifetime>
<wst:KeyType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer</wst:KeyType>
</wst:RequestSecurityTokenResponse>
</wst:RequestSecurityTokenResponseCollection>
</soap:Body>
</soap:Envelope>
Shared Signals: SSF, CAEP and RISC
Every Security Event Token (SET, RFC 8417)
is a JWT with typ secevent+jwt, signed with the realm key. The samples
below were collected over one poll stream
(RFC 8936). The receiver was a
client, ssf-rx, holding a client_credentials token with
ssf:read ssf:write:
curl -X POST https://127.0.0.1:38081/ssf/stream -H "Authorization: Bearer $SSF_TOKEN" \
-H 'content-type: application/json' -d '{"delivery":{"method":"urn:ietf:rfc:8936"}}'
# PATCH /ssf/stream with events_requested = every entry of events_supported, then:
curl -X POST https://127.0.0.1:38081/ssf/poll -H "Authorization: Bearer $SSF_TOKEN" \
-H 'content-type: application/json' \
-d '{"stream_id":"ssf-cMy49a2ttnFFG6ot","maxEvents":50,"returnImmediately":true}'
aud is the receiver’s client id, which the transmitter assigns.
The header is the same on every SET:
{
"alg": "RS256",
"typ": "secevent+jwt",
"kid": "sts-f7045241e6b0",
"x5u": "https://127.0.0.1:38081/pki/chain/default/8f1e19cfeec3d56c499825b1ef7094961166198463b14e301914bef595c199dc.pem"
}
Some of the events below were caused by real activity: a sign-in, a single
sign-on, a sign-out, an administrator setting a password, and disabling and
re-enabling an account. The rest were sent by hand with
POST /admin-api/ssf/transmit, because this service never emits them itself.
CAEP events says which activity fires which event.
Two issuers appear in these samples. The events raised through
/admin-api (credential-change, account-disabled, account-enabled)
name the person as iss https://127.0.0.1:8081, which is the container’s
internal listener, and not as the published issuer. That is a bug,
#154. The samples are shown
as the service sent them.
SSF
Verification
Sent on POST /ssf/verify (or the console’s Verify). It carries state when the receiver sent one. Its subject is the stream itself.
{
"iss": "https://127.0.0.1:38081",
"jti": "mnQjCurB2txPRWVRIDaJEA",
"iat": 1790110571,
"aud": "ssf-rx",
"events": {
"https://schemas.openid.net/secevent/ssf/event-type/verification": {}
},
"sub_id": {
"format": "opaque",
"id": "ssf-cMy49a2ttnFFG6ot"
},
"txn": "iZB_-Umc5JkSVGFNvJNTzw"
}
CAEP
The three session events name a complex subject: the person as
iss_sub and the session as opaque. The session id and ext_id are
the sid of the ID Token above.
session-established
Fired by the sign-in at /authn/login during the authorization code flow above.
{
"iss": "https://127.0.0.1:38081",
"jti": "VPXnmadXSJRyYbCV_ri_sA",
"iat": 1790110476,
"aud": "ssf-rx",
"events": {
"https://schemas.openid.net/secevent/caep/event-type/session-established": {
"acr": "1",
"amr": [
"pwd"
],
"ext_id": "sHiKmHBkOJ6bjKXM-TnFoHzZPEPIzHS7",
"event_timestamp": 1790110476,
"initiating_entity": "user",
"reason_admin": {
"en": "A session was created at OAuth 2.0 / OIDC."
},
"reason_user": {
"en": "You signed in."
}
}
},
"sub_id": {
"format": "complex",
"user": {
"format": "iss_sub",
"iss": "https://127.0.0.1:38081",
"sub": "urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2"
},
"session": {
"format": "opaque",
"id": "sHiKmHBkOJ6bjKXM-TnFoHzZPEPIzHS7"
}
},
"txn": "9NRAdwIDAzNU4-8kbzCGFg",
"toe": 1790110476
}
session-presented
Fired when an existing session answered a request without a new sign-in. This one is the WS-Federation sign-in above.
{
"iss": "https://127.0.0.1:38081",
"jti": "BBa96owRaHR4UKAYycTLkQ",
"iat": 1790110528,
"aud": "ssf-rx",
"events": {
"https://schemas.openid.net/secevent/caep/event-type/session-presented": {
"ext_id": "sHiKmHBkOJ6bjKXM-TnFoHzZPEPIzHS7",
"event_timestamp": 1790110528,
"initiating_entity": "user",
"reason_admin": {
"en": "An existing session was presented at WS-Federation and honoured without a new authentication."
},
"reason_user": {
"en": "You are still signed in."
}
}
},
"sub_id": {
"format": "complex",
"user": {
"format": "iss_sub",
"iss": "https://127.0.0.1:38081",
"sub": "urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2"
},
"session": {
"format": "opaque",
"id": "sHiKmHBkOJ6bjKXM-TnFoHzZPEPIzHS7"
}
},
"txn": "7iQf_1gihJMXVEC1qn6-9A",
"toe": 1790110528
}
session-revoked
Fired by POST /logout.
{
"iss": "https://127.0.0.1:38081",
"jti": "s4pCl7gHfZGd1XlkR9nOrA",
"iat": 1790110536,
"aud": "ssf-rx",
"events": {
"https://schemas.openid.net/secevent/caep/event-type/session-revoked": {
"event_timestamp": 1790110536,
"initiating_entity": "user",
"reason_admin": {
"en": "The session was ended by the person's own sign-out at /logout."
},
"reason_user": {
"en": "You have been signed out."
}
}
},
"sub_id": {
"format": "complex",
"user": {
"format": "iss_sub",
"iss": "https://127.0.0.1:38081",
"sub": "urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2"
},
"session": {
"format": "opaque",
"id": "sHiKmHBkOJ6bjKXM-TnFoHzZPEPIzHS7"
}
},
"txn": "3oL4KMucm0QVAfk09q8Uhw",
"toe": 1790110536
}
credential-change
Fired by POST /admin-api/users/set-password.
{
"iss": "https://127.0.0.1:38081",
"jti": "nBdeGRGur0rpfSbxw3tV2g",
"iat": 1790110559,
"aud": "ssf-rx",
"events": {
"https://schemas.openid.net/secevent/caep/event-type/credential-change": {
"credential_type": "password",
"change_type": "update",
"event_timestamp": 1790110559,
"initiating_entity": "admin",
"reason_admin": {
"en": "An administrator set the password of alice."
},
"reason_user": {
"en": "Your password was changed by an administrator."
}
}
},
"sub_id": {
"format": "complex",
"user": {
"format": "iss_sub",
"iss": "https://127.0.0.1:8081",
"sub": "urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2"
}
},
"txn": "a4Jfe1Nf6ld5wf5ZPM0OwQ",
"toe": 1790110559
}
assurance-level-change
Sent by hand here. The service sends it itself when a re-authentication on a held session moves its acr.
{
"iss": "https://127.0.0.1:38081",
"jti": "NSe-3rAIDD7P8kUM4zYDbQ",
"iat": 1790110571,
"aud": "ssf-rx",
"events": {
"https://schemas.openid.net/secevent/caep/event-type/assurance-level-change": {
"namespace": "NIST-AAL",
"current_level": "nist-aal2",
"previous_level": "nist-aal1",
"change_direction": "increase"
}
},
"sub_id": {
"format": "email",
"email": "alice@example.com"
},
"txn": "pBA_-Oe8CPZhzB4HXKQO1A"
}
token-claims-change
Sent by hand here. The service sends it itself only when a GNAP grant is modified.
{
"iss": "https://127.0.0.1:38081",
"jti": "pQOOOm99qLRUKLMRNrdn3w",
"iat": 1790110571,
"aud": "ssf-rx",
"events": {
"https://schemas.openid.net/secevent/caep/event-type/token-claims-change": {
"claims": {
"role": "auditor"
}
}
},
"sub_id": {
"format": "email",
"email": "alice@example.com"
},
"txn": "JuweC6L-kRdQGgOm-mzRew"
}
device-compliance-change
By hand only. This service knows nothing about devices.
{
"iss": "https://127.0.0.1:38081",
"jti": "Lh8h4QKp7UjdfHydmyr7Ag",
"iat": 1790110571,
"aud": "ssf-rx",
"events": {
"https://schemas.openid.net/secevent/caep/event-type/device-compliance-change": {
"previous_status": "compliant",
"current_status": "not-compliant"
}
},
"sub_id": {
"format": "email",
"email": "alice@example.com"
},
"txn": "CsKS0c0rsxlvOlswIJ4w0A"
}
risk-level-change
By hand only.
{
"iss": "https://127.0.0.1:38081",
"jti": "Qd5oy6GTEMoB-z4tqiAjDg",
"iat": 1790110571,
"aud": "ssf-rx",
"events": {
"https://schemas.openid.net/secevent/caep/event-type/risk-level-change": {
"risk_reason": "PASSWORD_FOUND_IN_DATA_BREACH",
"principal": "USER",
"current_level": "HIGH",
"previous_level": "LOW"
}
},
"sub_id": {
"format": "email",
"email": "alice@example.com"
},
"txn": "pdpXvtZKBbs3zghHf3edDA"
}
RISC
account-disabled
Fired by POST /admin-api/users/disable. reason is RISC’s own vocabulary (hijacking or bulk-account), not the reason the administrator typed.
{
"iss": "https://127.0.0.1:38081",
"jti": "KpKt8ECvyQk3im11paKRag",
"iat": 1790110559,
"aud": "ssf-rx",
"events": {
"https://schemas.openid.net/secevent/risc/event-type/account-disabled": {
"reason": "hijacking"
}
},
"sub_id": {
"format": "iss_sub",
"iss": "https://127.0.0.1:8081",
"sub": "urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2"
},
"txn": "_EnfF5XOyfQ4MzP6-NDFUg"
}
account-enabled
Fired by POST /admin-api/users/enable.
{
"iss": "https://127.0.0.1:38081",
"jti": "x03WcUA4TYZBVm84NypZDA",
"iat": 1790110559,
"aud": "ssf-rx",
"events": {
"https://schemas.openid.net/secevent/risc/event-type/account-enabled": {}
},
"sub_id": {
"format": "iss_sub",
"iss": "https://127.0.0.1:8081",
"sub": "urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2"
},
"txn": "W6rAiUdeXzKbZSx95lsg7w"
}
credential-compromise
Sent by hand, with an email subject.
{
"iss": "https://127.0.0.1:38081",
"jti": "YpW-W746iSJ_q258fXPMPw",
"iat": 1790110571,
"aud": "ssf-rx",
"events": {
"https://schemas.openid.net/secevent/risc/event-type/credential-compromise": {
"credential_type": "password",
"reason_admin": {
"en": "Found in a public breach corpus"
}
}
},
"sub_id": {
"format": "email",
"email": "alice@example.com"
},
"txn": "4cSRX3kV7qfrJq7-F59yaA"
}
account-credential-change-required
Sent by hand.
{
"iss": "https://127.0.0.1:38081",
"jti": "Rf1xRliQ4DQI0DhDO1T9eQ",
"iat": 1790110571,
"aud": "ssf-rx",
"events": {
"https://schemas.openid.net/secevent/risc/event-type/account-credential-change-required": {}
},
"sub_id": {
"format": "email",
"email": "alice@example.com"
},
"txn": "4tLrbUmuf5-X4E8Q1k9l1g"
}
identifier-changed
Sent by hand.
{
"iss": "https://127.0.0.1:38081",
"jti": "QSAMuGxUykMMhasLwaunog",
"iat": 1790110571,
"aud": "ssf-rx",
"events": {
"https://schemas.openid.net/secevent/risc/event-type/identifier-changed": {
"new-value": "alice.new@example.com"
}
},
"sub_id": {
"format": "email",
"email": "alice@example.com"
},
"txn": "9cGK_HN1GDiXOp9duG_Biw"
}
The stream also offers the rest of RISC: account-purged,
identifier-recycled, opt-in, the three opt-out-* events,
recovery-activated, recovery-information-changed and sessions-revoked.
It offers urn:iya:sts:secevent:event-type:signing-key-rotated, this
service’s own event, too. GET /admin/risc and GET /admin-api/risc list
what each carries.
Verifiable credentials and status lists
Issued at POST /oid4vci/credential (OpenID4VCI 1.0)
with an access token and a holder key proof (openid4vci-proof+jwt, ES256,
the holder’s public key in the header):
curl -X POST https://127.0.0.1:38081/oid4vci/nonce # c_nonce for the proof
curl -X POST https://127.0.0.1:38081/oid4vci/credential \
-H "Authorization: Bearer $ACCESS_TOKEN" -H 'content-type: application/json' \
-d '{"credential_configuration_id":"IdentityCredential","proofs":{"jwt":["<proof JWT>"]}}'
The claim values (Alice Anderson of Westerveld) are invented in development mode.
SD-JWT VC (dc+sd-jwt)
The issuer-signed JWT, then one ~-separated disclosure per selectively
disclosable claim, then a trailing ~. Each disclosure is
[salt, name, value], and its SHA-256 is one of the _sd digests. There is
one more digest than disclosures because a decoy is added. cnf.jwk is the
holder’s key, which a presentation must prove.
Encoded (shortened):
eyJhbGciOiJSUzI1NiIsInR5cCI6ImRjK3NkLWp3dCIsImtpZCI6InN0cy1m…3m3pJKQqQq-XHjPUIsPg~WyJGaEhsck1oWmJI…~WyJfejE3NjJtZjVk…~WyJCY0wtcGREX3dK…~WyJoWFh3U1hidkZi…~WyJlRUc2VS11NTR0…~WyJ3ZGFSOUhvc2xR…~
Header:
{
"alg": "RS256",
"typ": "dc+sd-jwt",
"kid": "sts-f7045241e6b0",
"x5u": "https://127.0.0.1:38081/pki/chain/default/8f1e19cfeec3d56c499825b1ef7094961166198463b14e301914bef595c199dc.pem"
}
Payload:
{
"iss": "https://127.0.0.1:38081",
"nbf": 1790110682,
"exp": 1792702682,
"vct": "urn:idptools:sd-jwt-vc:identity",
"sub": "urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2",
"cnf": {
"jwk": {
"kty": "EC",
"x": "T56NwGCCM6FWeBpoJIXpVxASLzbxE9TkGJ29oO622CY",
"y": "XFcU4uYxBhdq4G-tz_Z6HBNfRVcmuXjMlICdOSQaUhk",
"crv": "P-256"
}
},
"_sd_alg": "sha-256",
"_sd": [
"7-DGNIlsgYtNCIGq01d8U8qeE40t1hhuw0B2Qeay6gw",
"SZR3t2JV4EIg5cGRnm-oE3h3l14Rv04pkbJDUVe4-R4",
"_s37ZRac8qdhgXJcYZkKiJLp49qfpAtXdJBoe1l9JSs",
"b-a5FduugSreiCYHR1sNCMUNbt_8MfriGBGvwLXbrBk",
"dwKjCC17sqAbYZSD0uSKUbNctU46oR8XZIsjjmFtWFo",
"lA810L3YgLw2-0PZTFGxeiOY5eOsKjT6lSMOhGoSQxc",
"usOTLd-t5k8amUP5khn06KJKQ2mvr42FiifEEUojsmQ"
],
"status": {
"status_list": {
"idx": 13809,
"uri": "https://127.0.0.1:38081/oid4vci/status-lists/1"
}
},
"iat": 1790110682
}
Disclosures, decoded:
["FhHlrMhZbHKmcSYz45Ojjw", "given_name", "Alice"]
["_z1762mf5d_MaoA3X758ug", "family_name", "Anderson"]
["BcL-pdD_wJzfmjOVha7RYg", "email", "alice@example.com"]
["hXXwSXbvFbsQMC6seLYPtQ", "birthdate", "1967-11-16"]
["eEG6U-u54tmIlDtWSYBk8Q", "nationality", "NL"]
["wdaR9HoslQAJ6O-Dcsh2iA", "address", {"street_address": "891 Mock Lane", "locality": "Westerveld", "region": "Utrecht", "postal_code": "4395 LG", "country": "NL"}]
W3C VC as a JWT (jwt_vc_json)
The VC Data Model 1.1 credential inside a vc claim. credentialStatus
points at the two Bitstring Status Lists, and status at the Token Status
List.
Encoded (shortened):
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InN0cy1mNzA0NTI0…WrQRR1-UqEIz-GmtgeHA
Header:
{
"alg": "RS256",
"typ": "JWT",
"kid": "sts-f7045241e6b0",
"x5u": "https://127.0.0.1:38081/pki/chain/default/8f1e19cfeec3d56c499825b1ef7094961166198463b14e301914bef595c199dc.pem"
}
Payload:
{
"iss": "https://127.0.0.1:38081",
"sub": "urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2",
"nbf": 1790110682,
"exp": 1792702682,
"jti": "urn:uuid:7d806f49-86f8-4170-a75c-bce9a9e8622f",
"cnf": {
"jwk": {
"kty": "EC",
"x": "T56NwGCCM6FWeBpoJIXpVxASLzbxE9TkGJ29oO622CY",
"y": "XFcU4uYxBhdq4G-tz_Z6HBNfRVcmuXjMlICdOSQaUhk",
"crv": "P-256"
}
},
"vc": {
"@context": [
"https://www.w3.org/2018/credentials/v1"
],
"type": [
"VerifiableCredential",
"IdentityCredential"
],
"issuer": "https://127.0.0.1:38081",
"issuanceDate": "2026-09-22T20:58:02.000Z",
"expirationDate": "2026-10-22T20:58:02.000Z",
"credentialSubject": {
"id": "urn:uuid:016dc8f1-1bc4-55d9-9657-9b2ebb3cd4d2",
"given_name": "Alice",
"family_name": "Anderson",
"email": "alice@example.com",
"birthdate": "1967-11-16",
"nationality": "NL",
"address": {
"street_address": "891 Mock Lane",
"locality": "Westerveld",
"region": "Utrecht",
"postal_code": "4395 LG",
"country": "NL"
}
},
"credentialStatus": [
{
"id": "https://127.0.0.1:38081/oid4vci/status-lists/bitstring/revocation#14156",
"type": "BitstringStatusListEntry",
"statusPurpose": "revocation",
"statusListIndex": "14156",
"statusListCredential": "https://127.0.0.1:38081/oid4vci/status-lists/bitstring/revocation"
},
{
"id": "https://127.0.0.1:38081/oid4vci/status-lists/bitstring/suspension#14156",
"type": "BitstringStatusListEntry",
"statusPurpose": "suspension",
"statusListIndex": "14156",
"statusListCredential": "https://127.0.0.1:38081/oid4vci/status-lists/bitstring/suspension"
}
]
},
"status": {
"status_list": {
"idx": 14156,
"uri": "https://127.0.0.1:38081/oid4vci/status-lists/1"
}
},
"iat": 1790110682
}
W3C VC with a Data Integrity proof (ldp_vc)
VC Data Model 2.0, JSON-LD, signed with a bbs-2023 Data Integrity proof so
a holder can derive a selective-disclosure proof from it. The subject id is
the holder’s key as a did:jwk.
{
"@context": [
"https://www.w3.org/ns/credentials/v2",
"https://idptools.com/contexts/identity/v1"
],
"type": [
"VerifiableCredential",
"IdentityCredential"
],
"issuer": "https://127.0.0.1:38081",
"validFrom": "2026-09-22T20:58:09.000Z",
"validUntil": "2026-10-22T20:58:09.000Z",
"credentialSubject": {
"id": "did:jwk:eyJrdHkiOiJFQyIsImNydiI6IlAtMjU2IiwieCI6ImowZ09DTkVsTGMzbVpZdjBlVHVIVDlFVno3N2NzdW1rQ0tDd2cxODJMM0EiLCJ5IjoiU05tUUtLMlNRbFlCSXZmcE5ST2xnaXJ3NEtFQ2F6R1FJaVdTbDU4WThMbyJ9",
"given_name": "Alice",
"family_name": "Anderson",
"email": "alice@example.com",
"birthDate": "1967-11-16",
"nationality": "NL",
"streetAddress": "891 Mock Lane",
"locality": "Westerveld",
"region": "Utrecht",
"country": "NL"
},
"credentialStatus": [
{
"id": "https://127.0.0.1:38081/oid4vci/status-lists/bitstring/revocation#96646",
"type": "BitstringStatusListEntry",
"statusPurpose": "revocation",
"statusListIndex": "96646",
"statusListCredential": "https://127.0.0.1:38081/oid4vci/status-lists/bitstring/revocation"
},
{
"id": "https://127.0.0.1:38081/oid4vci/status-lists/bitstring/suspension#96646",
"type": "BitstringStatusListEntry",
"statusPurpose": "suspension",
"statusListIndex": "96646",
"statusListCredential": "https://127.0.0.1:38081/oid4vci/status-lists/bitstring/suspension"
}
],
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "bbs-2023",
"proofPurpose": "assertionMethod",
"verificationMethod": "https://127.0.0.1:38081/bbs/keys/bbs-urHoxY0-JItkTvDkQZ7ODM",
"created": "2026-09-22T20:58:09.000Z",
"proofValue": "ulY6hpQE-w5iRcHt3KOvIMbcbTpPB-cX7gXT7bedR_amgyOL79FwXBe2PUEL6v4MKRhm_ugm1V-yq9kPZ6n03-c4Z-V_1rLYUzQzEshX8qNk"
}
}
Token Status List (statuslist+jwt)
GET /oid4vci/status-lists/1. lst is the zlib-compressed, base64url list,
bits per credential. The credential’s status.status_list.idx is its
position in the list.
Encoded (shortened):
eyJhbGciOiJSUzI1NiIsInR5cCI6InN0YXR1c2xpc3Qrand0Iiwia2lkIjoi…8K4IZIeEwJ2vrHB0woGw
Header:
{
"alg": "RS256",
"typ": "statuslist+jwt",
"kid": "sts-f7045241e6b0",
"x5u": "https://127.0.0.1:38081/pki/chain/default/8f1e19cfeec3d56c499825b1ef7094961166198463b14e301914bef595c199dc.pem"
}
Payload:
{
"sub": "https://127.0.0.1:38081/oid4vci/status-lists/1",
"iat": 1790110695,
"exp": 1790197095,
"ttl": 300,
"status_list": {
"bits": 2,
"lst": "eNrtwQEBAAAAgJD-r-4ICgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYgAAAAQ",
"aggregation_uri": "https://127.0.0.1:38081/oid4vci/status-lists"
}
}
Bitstring Status List credential (vc+jwt)
GET /oid4vci/status-lists/bitstring/revocation (and …/suspension).
encodedList is the multibase, GZIP-compressed bitstring.
Encoded (shortened):
eyJhbGciOiJSUzI1NiIsInR5cCI6InZjK2p3dCIsImtpZCI6InN0cy1mNzA0…MndHy4ilnGEWuBI8aBqg
Header:
{
"alg": "RS256",
"typ": "vc+jwt",
"kid": "sts-f7045241e6b0",
"x5u": "https://127.0.0.1:38081/pki/chain/default/8f1e19cfeec3d56c499825b1ef7094961166198463b14e301914bef595c199dc.pem",
"cty": "vc"
}
Payload:
{
"iat": 1790110695,
"@context": [
"https://www.w3.org/ns/credentials/v2"
],
"id": "https://127.0.0.1:38081/oid4vci/status-lists/bitstring/revocation",
"type": [
"VerifiableCredential",
"BitstringStatusListCredential"
],
"issuer": "https://127.0.0.1:38081",
"validFrom": "2026-09-22T20:58:15.730Z",
"validUntil": "2026-09-23T20:58:15.730Z",
"credentialSubject": {
"id": "https://127.0.0.1:38081/oid4vci/status-lists/bitstring/revocation#list",
"type": "BitstringStatusList",
"statusPurpose": "revocation",
"encodedList": "uH4sIAAAAAAACA-3BMQEAAADCoPVPbQwfoAAAAAAAAAAAAAAAAAAAAIC3AYbSVKsAQAAA",
"ttl": 300000
}
}
OpenID4VP request object (oauth-authz-req+jwt)
This service’s verifier asks a wallet for a presentation with a signed
request object, passed by reference
(OpenID4VP 1.0,
RFC 9101). GET /oid4vp/start?by=reference sends the browser to the wallet
with request_uri, and the wallet fetches the object from
/oid4vp/request/{id}. The query is DCQL. The long algorithm lists in
client_metadata are shortened here.
Encoded (shortened):
eyJhbGciOiJSUzI1NiIsInR5cCI6Im9hdXRoLWF1dGh6LXJlcStqd3QiLCJr…5TwyyUHNDoTzk47sXpyw
Header:
{
"alg": "RS256",
"typ": "oauth-authz-req+jwt",
"kid": "sts-f7045241e6b0",
"x5u": "https://127.0.0.1:38081/pki/chain/default/8f1e19cfeec3d56c499825b1ef7094961166198463b14e301914bef595c199dc.pem"
}
Payload:
{
"typ": "oauth-authz-req+jwt",
"iss": "sts-verifier",
"aud": "https://self-issued.me/v2",
"iat": 1790111229,
"exp": 1790111829,
"client_id": "sts-verifier",
"response_type": "vp_token",
"response_mode": "direct_post",
"response_uri": "https://127.0.0.1:38081/oid4vp/response",
"nonce": "nHqlPbFdh3r168UNnvQzRldQ",
"state": "O4JHL3lpztGoKFXcpSlrGiRI",
"dcql_query": {
"credentials": [
{
"id": "identity_credential",
"format": "dc+sd-jwt",
"meta": {
"vct_values": [
"urn:idptools:sd-jwt-vc:identity"
]
},
"claims": [
{
"path": [
"given_name"
]
},
{
"path": [
"family_name"
]
}
]
}
]
},
"client_metadata": {
"client_name": "Mock Verifier (bar door)",
"vp_formats_supported": {
"dc+sd-jwt": {
"sd-jwt_alg_values": [
"RS256",
"RS384",
"RS512",
"PS256",
"… 18 more, post-quantum included"
],
"kb-jwt_alg_values": [
"RS256",
"RS384",
"RS512",
"PS256",
"… 18 more, post-quantum included"
]
},
"jwt_vc_json": {
"alg_values": [
"RS256",
"RS384",
"RS512",
"PS256",
"… 18 more, post-quantum included"
]
},
"ldp_vc": {
"proof_type_values": [
"DataIntegrityProof"
],
"cryptosuite_values": [
"bbs-2023",
"ecdsa-jcs-2019",
"eddsa-jcs-2022",
"mldsa44-jcs-2024",
"… 1 more, post-quantum included"
]
}
}
}
}
Domain Linkage Credential
DIF Well Known DID Configuration.
GET /.well-known/did-configuration.json returns linked_dids, a list of JWT
credentials. Each one binds the realm’s did:web to its origin, signed by
the key the DID document names in kid. The header has no typ, as the
specification’s examples show.
Encoded (shortened):
eyJhbGciOiJSUzI1NiIsImtpZCI6ImRpZDp3ZWI6MTI3LjAuMC4xJTNBMzgw…M2-thfMMaiN-NA01buFQ
Header:
{
"alg": "RS256",
"kid": "did:web:127.0.0.1%3A38081#sts-f7045241e6b0"
}
Payload:
{
"iss": "did:web:127.0.0.1%3A38081",
"sub": "did:web:127.0.0.1%3A38081",
"nbf": 1790111229,
"exp": 1821647229,
"vc": {
"@context": [
"https://www.w3.org/2018/credentials/v1",
"https://identity.foundation/.well-known/did-configuration/v1"
],
"issuer": "did:web:127.0.0.1%3A38081",
"issuanceDate": "2026-09-22T21:07:09.000Z",
"expirationDate": "2027-09-22T21:07:09.000Z",
"type": [
"VerifiableCredential",
"DomainLinkageCredential"
],
"credentialSubject": {
"id": "did:web:127.0.0.1%3A38081",
"origin": "https://127.0.0.1:38081"
}
}
}
Credential Offer and the pre-authorized code grant
From the second start of the service (see the note at the top), so its keys differ from the samples above.
GET /issuer/offer?mode=cross-device draws a QR code for
a Credential Offer that carries a pre-authorized code, plus a
Transaction Code (tx_code) shown on the page to type into the wallet.
In development mode the offer is for oid4vci.offerUsername
(diploma.student), for anybody who asks. The QR code holds:
openid-credential-offer://?credential_offer=%7B%22credential_issuer%22%3A%22https%3A%2F%2F…rval%22%3A5%7D%7D%7D
credential_offer, decoded:
{
"credential_issuer": "https://127.0.0.1:38081",
"credential_configuration_ids": [
"IdentityCredential"
],
"grants": {
"urn:ietf:params:oauth:grant-type:pre-authorized_code": {
"pre-authorized_code": "pnX0EbzFOr_b9Mx4SI8LQFP0uewrC4uh",
"tx_code": {
"input_mode": "numeric",
"length": 5,
"description": "Type the 5-digit code shown by the issuer."
},
"interval": 5
}
}
}
The wallet redeems it at the token endpoint, and needs no client authentication and no browser:
curl -X POST https://127.0.0.1:38081/oauth2/token \
-d grant_type=urn:ietf:params:oauth:grant-type:pre-authorized_code \
-d pre-authorized_code=pnX0EbzFOr_b9Mx4SI8LQFP0uewrC4uh \
-d tx_code=90757
Issued access token payload:
{
"iss": "https://127.0.0.1:38081",
"sub": "",
"aud": "https://127.0.0.1:38081/resource",
"client_id": "",
"typ": "Bearer",
"jti": "ge_28dKJ77xm4FJRc0QjpA",
"iat": 1790111821,
"nbf": 1790111821,
"exp": 1790115421,
"username": "diploma.student",
"scope": "identity_credential",
"preferred_username": "diploma.student"
}
The empty sub and client_id are a bug,
#158.
Token Status List as a CWT (statuslist+cwt)
From the second start of the service (see the note at the top), so its keys differ from the samples above.
The same list as the statuslist+jwt above, asked for with
Accept: application/statuslist+cwt. It is a COSE_Sign1 (CBOR tag 18) and
516 bytes on the wire. In CBOR diagnostic notation, with the byte strings
shortened:
== COSE_Sign1:
18([
h'a20139010010781a6170706c69636174696f6e2f73746174…',
{
4: h'7374732d383532356132313866616665'
},
h'a502782e68747470733a2f2f3132372e302e302e313a3338…',
h'80c518f1d0700d317dbd8fb0f031d01d2b823313dc549242…'
])
== protected header:
{
1: -257,
16: "application/statuslist+cwt"
}
== payload (CWT claims):
{
2: "https://127.0.0.1:38081/oid4vci/status-lists/1",
6: 1790111855,
4: 1790198255,
65534: 300,
65533: {
"bits": 2,
"lst": h'78daedc101010000008090feafee080a0000000000000000…',
"aggregation_uri": "https://127.0.0.1:38081/oid4vci/status-lists"
}
}
The protected header’s 1: -257 is RS256, and 16 is the COSE typ. The
unprotected 4 is the kid (sts-8525a218fafe as bytes). In the payload,
2 is sub, 6 is iat, 4 is exp, 65534 is ttl and 65533 is
status_list, as the Token Status List draft registers them.
GNAP access tokens
GNAP (RFC 9635) mints all five
token formats that RFC 9767
registers. Each sample came from a
trusted client (gnapSkipInteraction) whose application entry sets
gnapAccessTokenFormat, with a request signed by the client’s ES256 key
(RFC 9421 HTTP message signatures):
POST /gnap
{"client":{"key":{"proof":"httpsig","jwk":{…}}},
"access_token":{"access":[{"type":"photo-api","actions":["read"],
"locations":["https://server.example.net/"]}]}}
The grant response (the same shape for every format; value shortened):
{
"instance_id": "J54DF-ILw6-vqJSzCvT4T9qj",
"access_token": {
"value": "eyJhbGciOiJSUzI1NiIsInR5cCI6Ik…4Ssgn6IN5TfYAj-LyOpw",
"access": [
{
"type": "photo-api",
"actions": [
"read"
],
"locations": [
"https://server.example.net/"
]
}
],
"expires_in": 3600,
"manage": {
"uri": "https://127.0.0.1:38081/gnap/token/iBBKdW3f7zLydoaN",
"access_token": {
"value": "AkHGlBseiXqlFhuJACFCtlbncsWs3NJT"
}
}
},
"continue": {
"access_token": {
"value": "Z0-4glFqjhKzQJrAlk5OdpPjakKwDGQG"
},
"uri": "https://127.0.0.1:38081/gnap/continue/CUvnTrawKo8DvEI5D3-_PtUR",
"wait": 5
}
}
Every format carries the same facts. These are the issuer, the audience (the
resource server), the client, the access array, the lifetime and the key
binding: the thumbprint of the client’s key, so the token is useless without
that key’s signature.
jwt-signed
The header’s typ is JWT, and GNAP is the payload’s typ claim.
GNAP says otherwise, which is
#157.
Encoded (shortened):
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InN0cy1mNzA0NTI0…4Ssgn6IN5TfYAj-LyOpw
Header:
{
"alg": "RS256",
"typ": "JWT",
"kid": "sts-f7045241e6b0",
"x5u": "https://127.0.0.1:38081/pki/chain/default/8f1e19cfeec3d56c499825b1ef7094961166198463b14e301914bef595c199dc.pem"
}
Payload:
{
"typ": "GNAP",
"iss": "https://127.0.0.1:38081/gnap",
"jti": "C8l0zf7_-QfFjHw6zyaP1Q",
"iat": 1790110754,
"nbf": 1790110754,
"exp": 1790114354,
"client_id": "gnap-docs-jwt-signed",
"access": [
{
"type": "photo-api",
"actions": [
"read"
],
"locations": [
"https://server.example.net/"
]
}
],
"aud": "https://127.0.0.1:38081/gnap/rs/resource",
"cnf": {
"jkt": "tW5j9hcg4YLCsPLrPSNOfQcPXW6g0hixgR072bGtsxA"
}
}
jwt-encrypted
The same JWT inside a JWE. This resource server registered no gnapJweKey,
so the JWE is dir / A256GCM under a key only this service holds, and the
resource server has to introspect it (POST /gnap/introspect).
Encoded (shortened):
eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwidHlwIjoiSldUIiwiY3R5…Ky2h5NzIJtr9svmztCbQ
JWE header:
{
"alg": "dir",
"enc": "A256GCM",
"typ": "JWT",
"cty": "JWT"
}
macaroon
The V2 binary format (base64url here). It has a location, an identifier and first-party caveats, chained with HMAC-SHA256 under a root key written to the resource server’s entry. The readable strings in it:
https://127.0.0.1:38081/gnap
gnap:v1:2qB1s07g0s3nrrm25eA7PA
gnap:iss=https://127.0.0.1:38081/gnap
gnap:iat=1790110754
gnap:client=gnap-docs-macaroon
gnap:cnf=jkt:bEtFh2pdKik85DdLdhq2jq0xbyI9furqsd55VzLyOi0
gnap:exp<1790114354
gnap:nbf>=1790110754
gnap:aud=https://127.0.0.1:38081/gnap/rs/resource
gnap:access=W3sidHlwZSI6InBob3RvLWFwaSIsImFjdGlvbnMiOlsicmVhZCJdLCJsb2NhdGlvbnMiOlsiaHR0cHM6Ly9zZXJ2ZXIuZXhhbXBsZS5uZXQvIl19XQ
The last caveat’s value is the access array as base64url JSON.
biscuit
A Biscuit v2 token: Protobuf, signed with Ed25519, and carrying Datalog facts
and checks. The root public key is at /gnap/keys. The readable strings are
the facts’ names and values:
gnap_token
RYX5EJ9FytWzKkymD1SpMg
issuer
https://127.0.0.1:38081/gnap
issued_at
expires
not_before
audience
https://127.0.0.1:38081/gnap/rs/resource
client_instance
gnap-docs-biscuit
access
{"type":"photo-api","actions":["read"],"locations":["https://server.example.net/"]}
access_type
photo-api
access_action
access_location
https://server.example.net/
cnf_jkt
Yek_TrhX6tKam2k4iBqdTF4hAp-tQGp2uJbZkQp9I4c
presented_key
zcap
A ZCAP-LD capability, base64url JSON on the wire. It has an eddsa-jcs-2022
Data Integrity proof (gnap.zcapCryptosuite) whose verification method is
in the controller document at /gnap/zcap/controller. The proof repeats the
capability’s @context; it is shortened here.
{
"@context": [
"https://w3id.org/zcap/v1",
"https://w3id.org/security/data-integrity/v2",
{
"@version": 1.1,
"gnap": "urn:ietf:params:gnap#",
"gnapIssuer": "gnap:iss",
"gnapSubject": "gnap:sub",
"gnapAudience": {
"@id": "gnap:aud",
"@type": "@json"
},
"gnapClient": "gnap:client",
"gnapAccess": {
"@id": "gnap:access",
"@type": "@json"
},
"gnapFlags": {
"@id": "gnap:flags",
"@type": "@json"
},
"gnapCnf": "gnap:cnf",
"gnapLabel": "gnap:label",
"gnapIssuedAt": {
"@id": "gnap:iat",
"@type": "@json"
},
"gnapNotBefore": {
"@id": "gnap:nbf",
"@type": "@json"
}
}
],
"id": "urn:gnap:token:7FSZ8N98os2ljiljtHc1MQ",
"parentCapability": "urn:zcap:root:https%3A%2F%2F127.0.0.1%3A38081%2Fgnap%2Frs%2Fresource",
"invocationTarget": "https://127.0.0.1:38081/gnap/rs/resource",
"controller": "urn:ietf:params:oauth:jwk-thumbprint:sha-256:wwdCppya3lKAlSneLpSsl3cs7_x166BTjrGwJcxpPLs",
"expires": "2026-09-22T21:59:14Z",
"allowedAction": [
"read"
],
"gnapIssuer": "https://127.0.0.1:38081/gnap",
"gnapAudience": [
"https://127.0.0.1:38081/gnap/rs/resource"
],
"gnapClient": "gnap-docs-zcap",
"gnapAccess": [
{
"type": "photo-api",
"actions": [
"read"
],
"locations": [
"https://server.example.net/"
]
}
],
"gnapFlags": [],
"gnapCnf": "jkt:wwdCppya3lKAlSneLpSsl3cs7_x166BTjrGwJcxpPLs",
"gnapIssuedAt": 1790110754,
"gnapNotBefore": 1790110754,
"proof": {
"type": "DataIntegrityProof",
"cryptosuite": "eddsa-jcs-2022",
"created": "2026-09-22T20:59:14Z",
"verificationMethod": "https://127.0.0.1:38081/gnap/zcap/controller#sts-eddsa-6ed79092",
"proofPurpose": "capabilityDelegation",
"capabilityChain": [
"urn:zcap:root:https%3A%2F%2F127.0.0.1%3A38081%2Fgnap%2Frs%2Fresource"
],
"@context": "…the capability's @context, repeated…",
"proofValue": "z4tcyp8xbdJgUAJb3GTmNB3xSUh4T2PeV25Xh8BqbAHo9Z3oR9AHfp335T5Lv8R84xBsHbiSM4vmjRwBQkCP6iysb"
}
}
SPIFFE SVIDs
From the SPIFFE Workload API over TCP (spiffe.workloadPort, 8092) with the
workload.spiffe.io: true metadata header. Development mode created a
registration entry for the unattested caller (spiffe.autoCreateEntries), so
the SPIFFE ID is spiffe://example.org/workload.
JWT-SVID (FetchJWTSVID, audience https://api.example.org)
Signed with the trust domain’s own JWT authority, which the trust bundle at
GET /spiffe/bundle publishes. It is not the OAuth key.
Encoded (shortened):
eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InNwaWZmZS1rbjZa…YaRAirn8opeoYFRuWX9A
Header:
{
"alg": "ES256",
"typ": "JWT",
"kid": "spiffe-kn6ZOo6KkJo4ix8i"
}
Payload:
{
"sub": "spiffe://example.org/workload",
"aud": "https://api.example.org",
"exp": 1790111092,
"iat": 1790110792,
"jti": "JlESUHZa0iSrOy07"
}
X509-SVID (FetchX509SVID)
The SPIFFE ID is the only URI SAN. The subject is SPIRE’s C=US, O=SPIRE,
the lifetime is one hour, and the issuer is the realm’s SPIFFE Issuing CA.
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
78:ff:fc:21:b3:fb:0b:35:8d:ad:2d:8b:a2:39:35:1f
Signature Algorithm: ecdsa-with-SHA256
Issuer: CN = sts SPIFFE Issuing CA (default), O = sts
Validity
Not Before: Sep 22 20:59:52 2026 GMT
Not After : Sep 22 21:59:52 2026 GMT
Subject: C = US, O = SPIRE
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Key Usage: critical
Digital Signature
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Subject Alternative Name:
URI:spiffe://example.org/workload
X509v3 Subject Key Identifier:
4B:1A:F6:5F:85:85:D2:FC:BC:10:8B:0B:A3:CE:CB:14:4D:93:27:BE
X509v3 Authority Key Identifier:
ED:DA:84:A3:4A:E2:BD:B5:A9:A5:5E:D7:92:D6:31:D3:37:1E:18:EA
X.509 certificates, CRLs and OCSP
Everything hangs from one Root CA, with an Intermediate per realm and an
Issuing CA per use (PKI). Each leaf carries its CRL distribution
points (HTTP and LDAP) and an OCSP responder in its AIA. Those point at the
plain-HTTP revocation listener (pki.httpPort, 8082). A container is told its
published name and ports with pki.distributionBaseUrl and
pki.distributionPort; this one was not, so its certificates say
localhost:8082.
Root CA
GET /pki/ca/service/root.cer (DER). Self-signed, valid for twenty years.
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
68:ee:8f:0f:cb:40:8b:34:17:43:a9:13:06:57:4f:90
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = sts Root CA, O = sts
Validity
Not Before: Sep 22 20:54:03 2026 GMT
Not After : Sep 22 20:54:03 2046 GMT
Subject: CN = sts Root CA, O = sts
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:TRUE
X509v3 Key Usage: critical
Digital Signature, Certificate Sign, CRL Sign
X509v3 Subject Key Identifier:
C0:37:CA:95:27:CC:AD:3E:B0:24:60:A5:C4:C0:94:32:B9:35:3B:29
X509v3 Authority Key Identifier:
C0:37:CA:95:27:CC:AD:3E:B0:24:60:A5:C4:C0:94:32:B9:35:3B:29
JOSE signing certificate (the key behind every JWT above)
The first certificate in the x5u chain of every JWT on this page.
GET /pki/chain/default/{sha256}.pem returns the leaf, the JOSE Signing CA,
the realm’s Intermediate and the Root:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
02:60:d0:8e:90:c2:88:75:2c:17:13:fd:94:a0:5c:0b
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = sts JOSE Signing CA (default), O = sts
Validity
Not Before: Sep 22 20:54:03 2026 GMT
Not After : Sep 22 20:54:03 2027 GMT
Subject: CN = JOSE signing (RS256), O = sts
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Key Usage: critical
Digital Signature, Non Repudiation, Key Encipherment
X509v3 Subject Key Identifier:
45:AA:BC:A0:E7:DA:28:62:D0:A3:4B:BF:C5:52:0E:EB:48:B9:CC:0C
X509v3 Authority Key Identifier:
BB:75:B0:19:EE:21:22:E5:55:1C:26:E5:56:68:8D:CB:B2:5A:F9:1B
X509v3 CRL Distribution Points:
Full Name:
URI:http://localhost:8082/pki/crl/default/jose.crl
Full Name:
URI:ldap://localhost:389/cn=jose,ou=crl,dc=example,dc=com?certificateRevocationList;binary
Authority Information Access:
OCSP - URI:http://localhost:8082/pki/ocsp/default/jose
CA Issuers - URI:http://localhost:8082/pki/ca/default/jose.cer
TLS server certificate
What the main port presents, issued by the TLS Issuing CA under the process Intermediate. The same certificate is served on LDAPS 636 and the debugger’s listener.
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
10:55:f5:57:f5:4c:a6:39:7e:b6:81:b7:11:3c:22:19
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = sts TLS Issuing CA (Process), O = sts
Validity
Not Before: Sep 22 20:54:03 2026 GMT
Not After : Sep 22 20:54:03 2027 GMT
Subject: CN = localhost, O = sts
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication
X509v3 Subject Alternative Name:
DNS:localhost, DNS:sts, DNS:sts-mock, DNS:sts.example.com, IP Address:127.0.0.1
X509v3 Subject Key Identifier:
03:2C:D5:97:BE:63:EB:5D:AC:12:91:6E:E4:F8:5C:7A:2B:B7:72:06
X509v3 Authority Key Identifier:
F5:A0:A6:C7:CA:81:F0:2E:F3:07:2F:B3:EF:46:57:C5:9D:66:D5:00
X509v3 CRL Distribution Points:
Full Name:
URI:http://localhost:8082/pki/crl/process/tls.crl
Full Name:
URI:ldap://localhost:389/cn=tls,ou=process,ou=crl,dc=example,dc=com?certificateRevocationList;binary
Authority Information Access:
OCSP - URI:http://localhost:8082/pki/ocsp/process/tls
CA Issuers - URI:http://localhost:8082/pki/ca/process/tls.cer
A certificate issued over EST
POST /.well-known/est/simpleenroll with a PKCS#10 request for CN=alice and
Basic authentication as alice. The response is a base64 PKCS#7
certs-only. The subject is built from the directory entry, not from the
request. The SAN is the person’s URN, and the EKU is client authentication.
ACME and SCEP issue from the same core, under their own Issuing CAs.
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes \
-keyout alice.key -subj /CN=alice -outform DER | base64 -w0 > alice.csr.b64
curl -u alice:x -X POST https://127.0.0.1:38081/.well-known/est/simpleenroll \
-H 'content-type: application/pkcs10' -H 'content-transfer-encoding: base64' \
--data-binary @alice.csr.b64
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
74:62:05:25:d1:b7:85:5b:bd:fa:ab:e3:57:64:d1:bc
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = sts EST Issuing CA (default), O = sts
Validity
Not Before: Sep 22 21:00:11 2026 GMT
Not After : Sep 22 21:00:11 2027 GMT
Subject: CN = alice, O = sts
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Client Authentication
X509v3 Subject Alternative Name:
URI:urn:sts:person:alice
X509v3 Subject Key Identifier:
DA:89:A9:EC:27:96:6B:C0:01:97:BC:EF:90:86:67:B2:89:01:79:DD
X509v3 Authority Key Identifier:
1F:F0:86:2A:DA:18:CA:69:6B:E0:69:7B:DF:E0:44:26:F8:67:CC:F0
X509v3 CRL Distribution Points:
Full Name:
URI:http://localhost:8082/pki/crl/default/est.crl
Full Name:
URI:ldap://localhost:389/cn=est,ou=crl,dc=example,dc=com?certificateRevocationList;binary
Authority Information Access:
OCSP - URI:http://localhost:8082/pki/ocsp/default/est
CA Issuers - URI:http://localhost:8082/pki/ca/default/est.cer
A certificate issued over ACME
From the second start of the service (see the note at the top), so its keys differ from the samples above.
ACME (RFC 8555) at /enroll/acme/directory. The account
is bound for life to a person or application by an External Account Binding
key (POST /admin-api/acme/create-eab, or the person’s own at
/portal/certificates). The identifier here is a permanent-identifier naming
the person, so the order is ready at once and there is
no challenge to answer. A DNS name has to be registered on the entry first.
The certificate profile is chosen with the order’s profile member,
from the nine the directory lists in meta.profiles.
The order, and the order after finalize:
{
"order": {
"status": "ready",
"expires": "2026-09-23T21:12:32.630Z",
"identifiers": [
{
"type": "permanent-identifier",
"value": "alice"
}
],
"profile": "tls-client",
"authorizations": [
"https://127.0.0.1:38081/enroll/acme/authz/emm2U1PGnhNnGGaORM2_"
],
"finalize": "https://127.0.0.1:38081/enroll/acme/order/T4w5dyfpcCBvRMFliJM6/finalize"
},
"finalized": {
"status": "valid",
"expires": "2026-09-23T21:12:32.630Z",
"identifiers": [
{
"type": "permanent-identifier",
"value": "alice"
}
],
"profile": "tls-client",
"authorizations": [
"https://127.0.0.1:38081/enroll/acme/authz/emm2U1PGnhNnGGaORM2_"
],
"finalize": "https://127.0.0.1:38081/enroll/acme/order/T4w5dyfpcCBvRMFliJM6/finalize",
"certificate": "https://127.0.0.1:38081/enroll/acme/cert/RWEdplGYTCybNVzCCn3Q"
}
}
The download is application/pem-certificate-chain: the leaf, the ACME
Issuing CA and the realm Intermediate, without the Root. The leaf:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
2c:d3:a1:51:d8:43:46:ca:2d:e8:b9:1d:a0:be:b5:f8
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = sts ACME Issuing CA (default), O = sts
Validity
Not Before: Sep 22 21:12:33 2026 GMT
Not After : Dec 21 21:12:33 2026 GMT
Subject: CN = alice, O = sts
Subject Public Key Info:
Public Key Algorithm: id-ecPublicKey
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Client Authentication
X509v3 Subject Alternative Name:
URI:urn:sts:person:alice
X509v3 Subject Key Identifier:
BC:CB:60:16:A3:73:9A:DE:86:01:25:52:98:0C:53:C9:94:9B:51:E8
X509v3 Authority Key Identifier:
A6:07:AB:33:2A:83:86:FC:AA:9B:9A:4C:7B:0D:55:33:69:76:88:17
X509v3 CRL Distribution Points:
Full Name:
URI:http://localhost:8082/pki/crl/default/acme.crl
Full Name:
URI:ldap://localhost:389/cn=acme,ou=crl,dc=example,dc=com?certificateRevocationList;binary
Authority Information Access:
OCSP - URI:http://localhost:8082/pki/ocsp/default/acme
CA Issuers - URI:http://localhost:8082/pki/ca/default/acme.cer
A certificate issued over SCEP
From the second start of the service (see the note at the top), so its keys differ from the samples above.
SCEP (RFC 8894) at /enroll/scep. The device gets the
RA certificate with GetCACert, then sends a PKIOperation. That is a CMS
SignedData, signed with a throwaway self-signed key, around an EnvelopedData
encrypted to the RA, which holds a PKCS#10 request with a challenge
password. The challenge is single-use, from
POST /admin-api/scep/create-challenge or the person’s own at
/portal/certificates.
{
"id": "scep-p-YWxpY2U-2c0fbc7e1ca942e7",
"challenge": "scep-p-YWxpY2U-2c0fbc7e1ca942e7.QmxDpVpDwaWEq32oBk_as8aOgDmjcPvr",
"profile": "tls-client",
"expiresAt": "2026-09-22T22:13:05.871Z",
"target": {
"kind": "person",
"id": "alice"
},
"entryUri": "urn:sts:person:alice",
"url": "https://127.0.0.1:38081/enroll/scep/tls-client"
}
The reply is a CertRep: a SignedData from the RA whose signed attributes
say messageType 3, pkiStatus 0 (SUCCESS), the request’s
transactionID, and a recipientNonce echoing its senderNonce. Inside
is an EnvelopedData, encrypted back to the requester’s self-signed key,
that holds a degenerate certs-only PKCS#7 with the certificate:
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
7a:65:f3:29:38:9d:9a:3b:77:82:3d:2e:78:fb:99:cb
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = sts SCEP Issuing CA (default), O = sts
Validity
Not Before: Sep 22 21:13:06 2026 GMT
Not After : Sep 22 21:13:06 2027 GMT
Subject: CN = alice, O = sts
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
X509v3 extensions:
X509v3 Basic Constraints: critical
CA:FALSE
X509v3 Key Usage: critical
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Client Authentication
X509v3 Subject Alternative Name:
URI:urn:sts:person:alice
X509v3 Subject Key Identifier:
7E:1B:D2:C2:3D:93:81:49:EF:FE:D4:4E:BA:35:98:19:2D:A1:1A:90
X509v3 Authority Key Identifier:
D4:0E:94:1F:62:A4:88:C3:44:7F:41:4A:C9:D3:D9:CC:99:0B:1C:E4
X509v3 CRL Distribution Points:
Full Name:
URI:http://localhost:8082/pki/crl/default/scep.crl
Full Name:
URI:ldap://localhost:389/cn=scep,ou=crl,dc=example,dc=com?certificateRevocationList;binary
Authority Information Access:
OCSP - URI:http://localhost:8082/pki/ocsp/default/scep
CA Issuers - URI:http://localhost:8082/pki/ca/default/scep.cer
CRL
GET http://localhost:8082/pki/crl/default/jose.crl (DER), signed by the CA
it lists for. It lasts pki.crlLifetimeMinutes (60), and its CRL number is a
timestamp in milliseconds.
Certificate Revocation List (CRL):
Version 2 (0x1)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN = sts JOSE Signing CA (default), O = sts
Last Update: Sep 22 20:57:34 2026 GMT
Next Update: Sep 22 21:57:34 2026 GMT
CRL extensions:
X509v3 CRL Number:
1790110654262
X509v3 Authority Key Identifier:
BB:75:B0:19:EE:21:22:E5:55:1C:26:E5:56:68:8D:CB:B2:5A:F9:1B
No Revoked Certificates.
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
…
OCSP response
For the JOSE signing certificate, from that CA’s responder
(http://localhost:8082/pki/ocsp/default/jose). The responder is the CA
itself, named by key hash, and it echoes the request’s nonce.
openssl ocsp -issuer jose-ca.pem -cert jose-leaf.pem \
-url http://localhost:8082/pki/ocsp/default/jose -resp_text
OCSP Response Data:
OCSP Response Status: successful (0x0)
Response Type: Basic OCSP Response
Version: 1 (0x0)
Responder Id: BB75B019EE2122E5551C26E556688DCBB25AF91B
Produced At: Sep 22 20:57:34 2026 GMT
Responses:
Certificate ID:
Hash Algorithm: sha1
Issuer Name Hash: 1964625C2BC22DA7BE4DE3CBCD13CBAFABDE23B9
Issuer Key Hash: BB75B019EE2122E5551C26E556688DCBB25AF91B
Serial Number: 0260D08E90C288752C1713FD94A05C0B
Cert Status: good
This Update: Sep 22 20:57:34 2026 GMT
Next Update: Sep 22 21:57:34 2026 GMT
Response Extensions:
OCSP Nonce:
0410766C8B3AF3B61BA5347C0AA115F1A96C
Signature Algorithm: sha256WithRSAEncryption
Signature Value:
…
Kerberos tickets, keytabs and SPNEGO
Tickets
From the KDC on port 88 with MIT Kerberos. In development mode every user
shares one password, password! (krb5.userPassword). A ticket is ASN.1 DER.
Its enc-part, which holds the session key, the client name, the times and
the authorization data, is encrypted under the service’s long-term key, so
only the service can read it.
# krb5.conf: [realms] EXAMPLE.COM = { kdc = <host>:88 }
kinit alice@EXAMPLE.COM # AS-REQ -> a TGT for krbtgt/EXAMPLE.COM
kvno HTTP/localhost@EXAMPLE.COM # TGS-REQ -> a service ticket
klist -e -f
Default principal: alice@EXAMPLE.COM
Valid starting Expires Service principal
09/22/2026 13:57:02 09/22/2026 23:57:02 krbtgt/EXAMPLE.COM@EXAMPLE.COM
Flags: IA, Etype (skey, tkt): aes256-cts-hmac-sha1-96, aes256-cts-hmac-sha1-96
09/22/2026 13:57:02 09/22/2026 23:57:02 HTTP/localhost@EXAMPLE.COM
Flags: A, Etype (skey, tkt): aes256-cts-hmac-sha1-96, aes256-cts-hmac-sha1-96
The service ticket for HTTP/localhost, as openssl asn1parse reads it.
It is Ticket ::= [APPLICATION 1] SEQUENCE { tkt-vno [0] 5, realm [1],
sname [2] { name-type 1 (NT-PRINCIPAL), name-string }, enc-part [3] {
etype [0] 18 (aes256-cts-hmac-sha1-96), kvno [1] 3, cipher [2] } }
(RFC 4120 section 5.3):
0:d=0 hl=4 l=1170 cons: appl [ 1 ]
4:d=1 hl=4 l=1166 cons: SEQUENCE
8:d=2 hl=2 l= 3 cons: cont [ 0 ]
10:d=3 hl=2 l= 1 prim: INTEGER :05
13:d=2 hl=2 l= 13 cons: cont [ 1 ]
15:d=3 hl=2 l= 11 prim: GENERALSTRING EXAMPLE.COM
28:d=2 hl=2 l= 28 cons: cont [ 2 ]
30:d=3 hl=2 l= 26 cons: SEQUENCE
32:d=4 hl=2 l= 3 cons: cont [ 0 ]
34:d=5 hl=2 l= 1 prim: INTEGER :01
37:d=4 hl=2 l= 19 cons: cont [ 1 ]
39:d=5 hl=2 l= 17 cons: SEQUENCE
41:d=6 hl=2 l= 4 prim: GENERALSTRING HTTP
47:d=6 hl=2 l= 9 prim: GENERALSTRING localhost
58:d=2 hl=4 l=1112 cons: cont [ 3 ]
62:d=3 hl=4 l=1108 cons: SEQUENCE
66:d=4 hl=2 l= 3 cons: cont [ 0 ]
68:d=5 hl=2 l= 1 prim: INTEGER :12
71:d=4 hl=2 l= 3 cons: cont [ 1 ]
73:d=5 hl=2 l= 1 prim: INTEGER :03
76:d=4 hl=4 l=1094 cons: cont [ 2 ]
80:d=5 hl=4 l=1090 prim: OCTET STRING [HEX DUMP]:93D80E21FD7CA924FF5486C8…
The same ticket, wrapped in an AP-REQ inside a SPNEGO token, is what a
browser sends to /authn/spnego in Authorization: Negotiate …; the
SPNEGO tokens below show one.
Keytab
From the second start of the service (see the note at the top), so its keys differ from the samples above.
An MIT keytab for a service principal, returned once (base64) when an administrator creates or rotates it:
curl -X POST https://127.0.0.1:38081/admin-api/kerberos/principals/create-service \
-H "Authorization: Bearer $ADMIN_TOKEN" -H 'content-type: application/json' \
-d '{"spn":"HTTP/app.example.com"}'
# .keytab is base64 in the reply; decode it, then:
klist -k -t -e -K HTTP_app.example.com.kvno3.keytab
Keytab name: FILE:HTTP_app.example.com.kvno3.keytab
KVNO Timestamp Principal
---- ------------------- ------------------------------------------------------
3 09/22/2026 14:14:31 HTTP/app.example.com@EXAMPLE.COM (aes256-cts-hmac-sha1-96) (0x3abb449a2e9a…)
3 09/22/2026 14:14:31 HTTP/app.example.com@EXAMPLE.COM (aes128-cts-hmac-sha1-96) (0x0b956665c16e…)
3 09/22/2026 14:14:31 HTTP/app.example.com@EXAMPLE.COM (aes256-cts-hmac-sha384-192) (0x160e0c189bb0…)
3 09/22/2026 14:14:31 HTTP/app.example.com@EXAMPLE.COM (aes128-cts-hmac-sha256-128) (0xf656e6175626…)
3 09/22/2026 14:14:31 HTTP/app.example.com@EXAMPLE.COM (DEPRECATED:arcfour-hmac) (0xd37871190f92…)
The key version is krb5.kvno (3) for every principal built from
configuration. One key per krb5.enctypes entry. The list includes RC4 by
default in development mode, as above; in product mode it never does, and no
keytab carries an RC4 key there
(#182).
SPNEGO tokens
From the second start of the service (see the note at the top), so its keys differ from the samples above.
curl --negotiate against /spnego/protected, with a
TGT from kinit as above. The request’s Authorization: Negotiate carries
a NegTokenInit (RFC 4178) wrapping the Kerberos AP-REQ:
0:d=0 hl=4 l=1470 cons: appl [ 0 ]
4:d=1 hl=2 l= 6 prim: OBJECT :1.3.6.1.5.5.2
12:d=1 hl=4 l=1458 cons: cont [ 0 ]
16:d=2 hl=4 l=1454 cons: SEQUENCE
20:d=3 hl=2 l= 13 cons: cont [ 0 ]
22:d=4 hl=2 l= 11 cons: SEQUENCE
24:d=5 hl=2 l= 9 prim: OBJECT :1.2.840.113554.1.2.2
35:d=3 hl=4 l=1435 cons: cont [ 2 ]
39:d=4 hl=4 l=1431 prim: OCTET STRING [HEX DUMP]:6082059306092A864886F71201020201006E8205…
1.3.6.1.5.5.2 is SPNEGO and 1.2.840.113554.1.2.2 is the Kerberos
mechanism. The octet string is the GSS-wrapped AP-REQ, which holds the
service ticket for HTTP/localhost. The 200 response’s
WWW-Authenticate: Negotiate carries a NegTokenResp: negState 0
(accept-completed), the mechanism, the AP-REP for mutual authentication, and
a mechListMIC:
0:d=0 hl=3 l= 215 cons: cont [ 1 ]
3:d=1 hl=3 l= 212 cons: SEQUENCE
6:d=2 hl=2 l= 3 cons: cont [ 0 ]
8:d=3 hl=2 l= 1 prim: ENUMERATED :00
11:d=2 hl=2 l= 11 cons: cont [ 1 ]
13:d=3 hl=2 l= 9 prim: OBJECT :1.2.840.113554.1.2.2
24:d=2 hl=3 l= 159 cons: cont [ 2 ]
27:d=3 hl=3 l= 156 prim: OCTET STRING [HEX DUMP]:60819906092A864886F71201020202006F818930…
186:d=2 hl=2 l= 30 cons: cont [ 3 ]
188:d=3 hl=2 l= 28 prim: OCTET STRING [HEX DUMP]:040405FFFFFFFFFF0000000000000000CFC78F39…
Second factors: TOTP and recovery codes
From the second start of the service (see the note at the top), so its keys differ from the samples above.
Neither is a token a client sees. They are secrets a
person is shown once, on /portal/mfa, after signing in to the portal.
TOTP secret (RFC 6238)
Set one up shows a QR code and the same values for typing in by hand. Nothing is stored until a code computed from the secret is typed back. This one was confirmed with a code computed from the secret below:
Secret OFCZ JCEU QJ4E DKF3 V3HD 3CDI NI6P Q6BZ (base32, 160 bits)
Account alice
Issuer 127.0.0.1:38081 (default)
Type Time based
Algorithm HMAC-SHA-1
Digits 6
Period 30 seconds
The QR code is drawn on the server as SVG, and encodes the same values as
an otpauth://totp/… key URI.
Recovery codes
Generate recovery codes shows a set of ten, once. It is stored only when the person confirms, and then only as one scrypt hash per code. Each code works once, in place of the second factor. Dashes and case are ignored.
27RIH-VXXXL 2B2DC-QAURI 2EOBM-YYFIF SWVG7-HA4KP G2CPX-EO426
ANIX7-K46ZZ TZ3QJ-PFAKS 76PY3-OZFXB QIF7B-OSI3G JS54N-7PT4F
Opaque values
Some things this service issues are deliberately not self-describing. They are random handles to a record on the server, and decoding one tells a client nothing:
| Value | Sample | Where |
|---|---|---|
| OAuth authorization code | qVqFgarG41wqzJk_HdOcC9ZJoLT5iY4A |
the code on the redirect back to the client |
| Stream id (SSF) | ssf-cMy49a2ttnFFG6ot |
POST /ssf/stream |
| GNAP token management access token | AkHGlBseiXqlFhuJACFCtlbncsWs3NJT |
access_token.manage in a grant response |
PAR request_uri (RFC 9126), second start |
urn:ietf:params:oauth:request_uri:pvwZ_Imv1VRnaDzuj1o-5eGh4TLepK1VaMHCjmSIWf4 |
POST /oauth2/par; lives 60 seconds and is spent at /oauth2/authorize |
| Client secret, second start | n7_Cj7ojyhHHACI1J2IR7Kj9B9XIt_3K |
POST /oauth2/register with client_secret_basic |
| Registration access token (RFC 7592), second start | lSSLd0otQHaXcF8OPP4Byjys_yc6J60o |
the same response, for GET/PUT/DELETE on registration_client_uri |
OpenID4VCI c_nonce, second start |
SL6XJugFSq0gDJHubS2J3Foc2lxdIDZ9 |
POST /oid4vci/nonce; goes in the key proof’s nonce |
| OpenID4VCI pre-authorized code and Transaction Code, second start | pnX0EbzFOr_b9Mx4SI8LQFP0uewrC4uh, 90757 |
a cross-device Credential Offer (above) |
| Password reset token, second start | LoxEJXPnfjFc3c-70gD-KOBT4HWQ0g7KjJKuttojU18 |
POST /admin-api/users/issue-password-reset returns https://…/portal/reset-password?user=alice&token=…; shown once, stored hashed |
Session sid |
sHiKmHBkOJ6bjKXM-TnFoHzZPEPIzHS7 |
the ID Token’s sid, the SAML SessionIndex, CAEP’s session subject |
Related
- Accepted tokens: which door accepts which of these.
- OAuth 2.0 and OpenID Connect,
Security profiles: what changes the access token and
ID Token (DPoP’s
cnf.jkt, mTLS’scnf.x5t#S256, encrypted ID Tokens). - SAML 2.0 Web Browser SSO, SAML 1.1, WS-Trust, WS-Federation.
- Shared Signals, CAEP events.
- OpenID4VCI and status lists, GNAP, SPIFFE, PKI, EST, Kerberos and SPNEGO.