Issue Description
When using an OIDC directory, the Name Claim setting has no effect and the Full Name (description) field is never populated on accounts.
The Name Claim field in the admin UI states: “…to retrieve the user’s display name from the token or user info response”. However, the userinfo endpoint is never called when the access token is a JWT containing an email claim.
Expected Behavior
When a Name Claim is configured (e.g. name or given_name), Stalwart should retrieve the user’s display name from either the JWT claims or the userinfo endpoint, as the UI description states. The Full Name field on the account should be populated after login.
Actual Behavior
The Full Name / description field remains empty after login, regardless of which Name Claim value is configured. Tested with both name and given_name
Reproduction Steps
1 Configure an OIDC directory (I used Rauthy)
2 Set the Name Claim to name or given_name.
3 Log in via the account portal.
4 Check the account in the admin UI, Full Name is empty.
Stalwart Version
v0.16.x
Installation Method
Docker
Database Backend
RocksDB
Blob Storage
RocksDB
Search Engine
Internal
Directory Backend
OIDC
Additional Context
In crates/directory/src/backend/oidc/lookup.rs, authenticate_jwt decides where to source claims:
let (email, claims) = if let Ok(email) = self.resolve_email(&token_data.claims) {
(email, token_data.claims) // JWT claims used for everything
} else {
let claims = self.fetch_userinfo(token).await?; // only called if email missing
(self.resolve_email(&claims)?, claims)
};
return self.build_account(email, &claims);
The userinfo endpoint is only called when email cannot be resolved from the JWT. When the access token contains the email claim, the userinfo endpoint is never reached.
build_account then extracts the name from whichever claims object was used, meaning the name claim can only ever be found if it is also present in the access token JWT:
description: self
.config
.claim_name
.as_ref()
.and_then(|name_claim| claims.get(name_claim))
.and_then(|v| v.as_str())
.map(|s| s.to_string()),
Per the OIDC specification, profile claims (name, given_name, family_name) belong in the id_token and userinfo endpoint, not in the access token. Rauthy explicitly follows this and does not include profile claims in the access token. This means the Name Claim feature is broken for any spec-compliant provider: email resolves from the JWT, userinfo is skipped, and the name claim is never found.
I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.
on
I have searched this support forum (open and closed topics) and confirm this is not a duplicate.
on
I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.
on