Aller au contenu principal
Version 0.3Brouillon

UserInfo endpoint

What the UserInfo endpoint returns

The UserInfo endpoint returns claims about the authenticated user as a JSON object, fetched with a valid access token.

It is defined in OIDC Core 1.0 §5.3 (opens in a new tab) and is the standard mechanism for fetching fresh profile data after the initial sign-in.

Endpoint:

https://login.luxid.lu/mga/sps/oauth/oauth20/userinfo

Both GET and POST are supported. The access token obtained from the Token endpoint must be supplied as a Bearer token.


When to call UserInfo vs read the ID Token

The ID token and the UserInfo endpoint both carry user claims, but they serve different purposes:

ID tokenUserInfo
Data freshnessSnapshot at authentication timeMost current data at call time
TransportEncoded in the token responseSeparate HTTP call
VerificationValidate signature with JWKSProtected by the Bearer token
Typical useSession establishment, SSODisplay profile, pre-fill forms
Rule of thumb

Use the ID token claims to establish the user's session and for security decisions (subject, assurance level, authentication time). Call UserInfo when you need the most current version of mutable data such as email address, phone number, or display name - particularly if the user may have changed these since they last authenticated.

See Tokens and claims for the full claims reference.


Request

GET /mga/sps/oauth/oauth20/userinfo HTTP/1.1
Host: login.luxid.lu
Authorization: Bearer <access_token>
Accept: application/json

POST request

POST /mga/sps/oauth/oauth20/userinfo HTTP/1.1
Host: login.luxid.lu
Content-Type: application/x-www-form-urlencoded

access_token=<access_token>

The GET form is preferred - the POST form is provided for environments where adding a request header is inconvenient (for example, some script-based tooling).


cURL examples

GET

curl -s \
-H "Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \
-H "Accept: application/json" \
https://login.luxid.lu/mga/sps/oauth/oauth20/userinfo

POST

curl -s \
-X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "access_token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..." \
https://login.luxid.lu/mga/sps/oauth/oauth20/userinfo

Response

The response is a JSON object. The claims returned are those in your Application's Claim Template on the LuxID side, subject to user consent. The scope parameter you sent at authorisation does not drive what is in the response - see Tokens and Claims - Requesting claims for the full claim model. The examples below illustrate typical Claim Template configurations.

Minimal response (Claim Template: openid only)

{
"sub": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

The sub claim is always present. It is the stable, opaque LuxID user identifier for your application. Do not display it to users - it is a technical identifier only.

Standard profile response (Claim Template includes name, email, phone)

{
"sub": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Jean Dupont",
"given_name": "Jean",
"family_name": "Dupont",
"email": "jean.dupont@example.lu",
"email_verified": true,
"phone_number": "+352691123456",
"phone_number_verified": true,
"updated_at": 1716374400
}

Extended response with assurance claims

{
"sub": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Jean Dupont",
"given_name": "Jean",
"family_name": "Dupont",
"email": "jean.dupont@example.lu",
"email_verified": true,
"phone_number": "+352691123456",
"phone_number_verified": true,
"updated_at": 1716374400,
"acr": "urn:luxid:acr:level:substantial",
"amr": ["pwd", "otp"],
"birthdate": "1985-03-14",
"address": {
"street_address": "42 Rue de la Liberté",
"locality": "Luxembourg",
"postal_code": "L-1930",
"country": "LU"
}
}

Claim descriptions

The OIDC standard groups claims under conceptual scopes (openid, profile, email, phone, address). LuxID lists them here for reference, but scope is not what gates release in LuxID - your Claim Template is. The "Standard scope group" column tells you which OIDC scope the claim conceptually belongs to.

ClaimTypeStandard scope groupDescription
substringopenidStable pairwise or public subject identifier
namestringprofileFull display name
given_namestringprofileFirst name(s)
family_namestringprofileFamily name
localestringprofileBCP 47 language tag (fr, de, lb, en)
updated_atintegerprofileUnix timestamp of last profile update
emailstringemailPrimary email address
email_verifiedbooleanemailWhether LuxID has verified the email
phone_numberstringphoneE.164 phone number
phone_number_verifiedbooleanphoneWhether LuxID has verified the number
birthdatestringprofileISO 8601 date of birth
addressobjectaddressOIDC address claim (structured)
acrstringopenidAuthentication Context Class Reference (assurance level)
amrarrayopenidAuthentication Methods References

Claims that are not in your Application's Claim Template are omitted from the response - they are not returned as null or empty strings. To add a claim, request a Claim Template update from LuxID.


How long to cache UserInfo responses

attention

Do not cache UserInfo responses for longer than the access token lifetime. The access token's exp claim (or the expires_in value from the token response) defines the upper bound.

Practical recommendations:

  • Short-lived sessions (under 5 minutes): skip caching - call UserInfo once per session.
  • Medium sessions (5-60 minutes): cache the response keyed by the access token, with a TTL equal to expires_in minus a small safety margin (for example, 30 seconds).
  • Long-lived sessions: do not cache at all if you need to display current email or phone - call UserInfo on each page load or on a short timer. Email and phone number can change.

The updated_at claim can help you decide whether to refresh: if updated_at is newer than your cached timestamp, discard the cache and re-fetch.


Claim availability

A claim is only returned if all of the following hold:

  1. The claim is in your Application's Claim Template on the LuxID side. The scope parameter you sent at authorisation does not gate claim release - adding a scope does not unlock a claim; only a Claim Template update does. See Tokens and Claims - Requesting claims.
  2. The user consented to sharing that claim with your application.
  3. The claim has a value in the user's LuxID profile (for example, address is only returned if the user has added an address - LuxID uses a progressive profile, so optional attributes are often absent).

Design your application to handle absent optional claims gracefully: an unprovided or non-consented claim is omitted entirely, not returned as null or an empty string. If a claim you expected is missing and it is not a consent or profile-value issue, the fix is a Claim Template update - contact LuxID.


Error responses

401 unauthorized - invalid or expired Access Token

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="invalid_token",
error_description="The access token is expired, revoked, or malformed"
{
"error": "invalid_token",
"error_description": "The access token is expired, revoked, or malformed"
}

Resolution: obtain a new access token via the Token endpoint using a refresh token, or re-initiate the authorisation flow. See Session management for silent renewal patterns.

401 unauthorized - missing bearer token

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="luxid"

Resolution: include the Authorization: Bearer <access_token> header.

403 forbidden - insufficient scope

HTTP/1.1 403 Forbidden
{
"error": "insufficient_scope",
"error_description": "The access token does not have the required scope to call UserInfo"
}

Resolution: ensure the access token was issued with at least the openid scope. Note that adding profile/email/phone scopes does not unlock additional claims at UserInfo - claim release is governed by your Claim Template, not the scope parameter. If a claim you need is missing, request a Claim Template update (see Claim availability above). For a partner-specific technical claim (luxid_<partner-prefix>_<name>), a Claim Template update is only half the fix: you must also set a value for the user via the Partner API claims capability - a declared-but-never-set technical claim is omitted.

404 not found

Returned if the user account has been deleted after the access token was issued.


Sequence diagram


Integration checklist

  • Request only the scopes your application actually needs - do not request profile email phone address if you only need sub.
  • Store sub as the user's stable identifier in your database - do not store or compare email addresses as identifiers.
  • Handle absent claims: email, phone_number, birthdate, and address may all be missing.
  • Cache responses responsibly: key by access token, TTL equal to expires_in.
  • Refresh on 401: implement silent token renewal before calling UserInfo again.
  • Verify that email_verified is true before treating an email address as confirmed.

Mise à jour le 2026-07-03