kappapilla
kappapilla5d ago

`scope` claim in JWT

looks like scope claim is modeled differently in Zitadel compared to Okta/KeyCloak. any reason and also is it complaint to Oauth2 spec? here are some example for dfferent Auth servers ZITADEL Implementation Scope Format:
# ZITADEL's proprietary URN format
openid urn:zitadel:iam:org:project:id:344374183645413380:aud urn:zitadel:iam:org:projects:roles
# ZITADEL's proprietary URN format
openid urn:zitadel:iam:org:project:id:344374183645413380:aud urn:zitadel:iam:org:projects:roles
JWT Structure:
{
"iss": "http://localhost:8082",
"sub": "345377791925026818",
"aud": ["344374183645413380"],
"exp": 1762400552,
"iat": 1762357352,
"client_id": "service_test-user-1762357206",
"urn:zitadel:iam:org:project:344374183645413380:roles": {
"streaming": {
"344373908297744388": "ea-1761758844.localhost"
}
}
}
{
"iss": "http://localhost:8082",
"sub": "345377791925026818",
"aud": ["344374183645413380"],
"exp": 1762400552,
"iat": 1762357352,
"client_id": "service_test-user-1762357206",
"urn:zitadel:iam:org:project:344374183645413380:roles": {
"streaming": {
"344373908297744388": "ea-1761758844.localhost"
}
}
}
Keycloak Implementation Scope Format:
# Standard OAuth2 scopes
openid profile email roles web-origins
# Standard OAuth2 scopes
openid profile email roles web-origins
JWT Structure:
{
"exp": 1699123456,
"iat": 1699120000,
"jti": "abc-123-def",
"iss": "http://localhost:8080/realms/master",
"aud": "account",
"sub": "service-account-client-id",
"typ": "Bearer",
"azp": "my-service",
"scope": "profile email roles",
"realm_access": {
"roles": ["admin", "user", "streaming"]
},
"resource_access": {
"my-service": {
"roles": ["service-role"]
}
},
"clientId": "my-service",
"clientHost": "127.0.0.1"
}
{
"exp": 1699123456,
"iat": 1699120000,
"jti": "abc-123-def",
"iss": "http://localhost:8080/realms/master",
"aud": "account",
"sub": "service-account-client-id",
"typ": "Bearer",
"azp": "my-service",
"scope": "profile email roles",
"realm_access": {
"roles": ["admin", "user", "streaming"]
},
"resource_access": {
"my-service": {
"roles": ["service-role"]
}
},
"clientId": "my-service",
"clientHost": "127.0.0.1"
}
Okta Implementation Scope Format:
# Dot notation scopes
openid groups okta.users.read custom.scope
# Dot notation scopes
openid groups okta.users.read custom.scope
JWT Structure:
{
"ver": 1,
"jti": "AT.abc123def456",
"iss": "https://dev-123456.okta.com/oauth2/default",
"aud": "api://default",
"iat": 1699120000,
"exp": 1699123600,
"cid": "client-id",
"uid": "service-user-id",
"scp": ["custom.scope", "okta.users.read"],
"sub": "service-user-id"
}
{
"ver": 1,
"jti": "AT.abc123def456",
"iss": "https://dev-123456.okta.com/oauth2/default",
"aud": "api://default",
"iat": 1699120000,
"exp": 1699123600,
"cid": "client-id",
"uid": "service-user-id",
"scp": ["custom.scope", "okta.users.read"],
"sub": "service-user-id"
}
3 Replies
Ask Inkeep
Ask Inkeep5d ago
Hi @kappapilla, I'm an AI assistant for ZITADEL. While a team member reviews this question, I'll see if I can find relevant sources for your question. Answer The scope claim behavior in ZITADEL JWT access tokens has been a known issue. According to RFC 8693, the scope claim should be returned in JWT access tokens (1) . However, there's a documented difference between how ZITADEL handles opaque versus JWT access tokens (2) . For opaque access tokens, the scope claim is included when you introspect the token . For JWT access tokens, the scope claim has historically not been included in the token itself . This appears to be a gap rather than intentional design. Access tokens configured as JWT (not opaque) should include the scope claim (1) . The Token Exchange grant in ZITADEL does return a scope field in the response, which contains the final scope of the obtained token (3) . Regarding OAuth2/OIDC compliance: ZITADEL's URN-based scope format (like urn:zitadel:iam:org:project:id:344374183645413380:aud) is used for audience control and role assertions, which is an extension beyond standard OAuth2 scopes but doesn't violate the spec (4) . Standard scopes like openid, profile, and email work as expected . If you need the scope claim in your JWT access tokens, you could: 1. Use opaque tokens and call the introspection endpoint (2) 2. Request both access and ID tokens with the openid scope (3) 3. Consider using Actions to add the scope claim to JWT tokens Would you like help with implementing any of these approac hes? ​ To learn more, see the sources I considered: [1] According to RFC 8693 "scope" is supposed to be returned in JWT Access token [2] Discord message from @zgrdaniel on 2024-06-11 [3] Impersonation and delegation using Token Exchange [4] OpenID Connect Endpoints in ZITADEL ​ Feel free to tag @Ask Inkeep with additional questions.
kappapilla
kappapillaOP5d ago
this is for service user and wondering if simple strings x.write available for service user scope claim.. @Ask Inkeep
Ask Inkeep
Ask Inkeep5d ago
Got it. Tagging @Rajat for additional help.

Did you find this page helpful?