Budibase/budibase · error
Could not determine user email from profile ${JSON.stringify
Error message
Could not determine user email from profile ${JSON.stringify(profile)} and claims ${JSON.stringify(jwtClaims)} What it means
getEmail resolves the user's email during OIDC SSO verification from the profile, then jwtClaims.email, then jwtClaims.preferred_username (if it is a valid email). If none of these yield a usable email it throws this error because Budibase requires an email identity to save/link the SSO user.
Source
Thrown at packages/backend-core/src/middleware/passport/sso/oidc.ts:150
*/
function getEmail(profile: SSOProfile, jwtClaims: JwtClaims) {
// profile not guaranteed to contain email e.g. github connected azure ad account
if (profile._json.email) {
return profile._json.email.toLowerCase()
}
// fallback to id token email
if (jwtClaims.email) {
return jwtClaims.email.toLowerCase()
}
// fallback to id token preferred username
const username = jwtClaims.preferred_username
if (username && validEmail(username)) {
return username.toLowerCase()
}
throw new Error(
`Could not determine user email from profile ${JSON.stringify(
profile
)} and claims ${JSON.stringify(jwtClaims)}`
)
}
/**
* Determines whether the identity provider has verified the email that
* getEmail resolved. Mirrors getEmail's source precedence so the returned flag
* describes the same claim. An absent email_verified is treated as unverified
* (OIDC Core §5.7). A preferred_username used as an email is never considered
* verified.
* @param profile The structured profile created by passport using the user info endpoint
* @param jwtClaims The claims returned in the id token
*/
function getEmailVerified(profile: SSOProfile, jwtClaims: JwtClaims): boolean {
if (profile._json.email) {
return profile._json.email_verified === trueView on GitHub (pinned to a81a902e9a)
Solutions
- Configure the OIDC provider to release the email scope and the email claim in the ID token/userinfo
- Set preferred_username to a valid email address on the IdP, or map a claim containing the user's email into preferred_username
- Check the profile JSON in the message to see exactly which claims the IdP is returning and adjust claim mapping
- If the IdP cannot provide emails, use a different authentication method or a connector that synthesizes emails
Example fix
// before (IdP returns preferred_username: "jdoe") // after: configure claim mapping so preferred_username = "jdoe@example.com" (or add scope "email")
Defensive patterns
Strategy: validation
Validate before calling
function hasUsableEmail(profile, jwtClaims) {
const candidates = [profile?.email, jwtClaims?.email, jwtClaims?.preferred_username]
return candidates.some(c => typeof c === "string" && /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(c))
} Type guard
function isEmail(value) {
return typeof value === "string" && /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(value)
} Try / catch
try {
await strategy.authenticate(req)
} catch (err) {
if (String(err.message).startsWith("Could not determine user email")) {
// surface a friendly 'your identity provider does not share your email' message
}
} Prevention
- Always request the 'email' (and 'profile') scopes in the OIDC client configuration
- Confirm with the IdP admin that email and preferred_username claims are released to your client
- Test login with a real IdP account before rollout and inspect returned claims
- Provide a claim mapping so an email-bearing claim populates preferred_username if needed
When it happens
Trigger: An OIDC IdP completes authentication but returns a profile and ID token with no email claim, no valid email-formatted claim values, and no preferred_username that parses as an email.
Common situations: IdPs that only return a subject ID or opaque username (e.g. username 'jdoe' with no @domain); email scope not requested/granted in the OIDC client config; IdP admin has not populated emails for users; custom enterprise IdPs with nonstandard claims.
Related errors
- Error constructing OIDC authentication strategy - ${err}
- Configuration invalid. Must contain clientID, clientSecret,
- Configuration cannot be deactivated while SSO is enforced
- Configuration invalid. Must contain google clientID and clie
- Error constructing google authentication strategy: ${err}
AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29).
Data as JSON: /api/errors/4a1875495c5382bc.
Report an issue: GitHub.