Token Endpoint¶
At the end of the authentication flow described at the previous section, the RP sends a request to the Token Endpoint with the authorization code received by the OP. These tokens MUST be signed JWT.
The Token response, if succesfull, returns an ID Token, an Access Token and possibly a Refresh Token (if the authentication request has scope=offline_access and prompt=consent. See Section Refresh Token.).
Note
The authentication method of the RP by the Token Endpoint is the private_key_jwt (OpenID.Core#ClientAuthentication)
See also
Request¶
The claims that MUST be included in the Token Request are given below.
Request example with authorization code (case 1)
POST /token HTTP/1.1 Host: https://op.spid.agid.gov.it Content-Type: application/x-www-form-urlencoded client_id=https://rp.spid.agid.gov.it& client_assertion=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiw ibmFtZSI6IlNQSUQiLCJhZG1pbiI6dHJ1ZX0.LVyRDPVJm0S9q7oiXcYVIIqGWY0wWQlqxvFGYswL…& client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwtbearer& code=usDwMnEzJPpG5oaV8x3j& code_verifier=9g8S40MozM3NSqjHnhi7OnsE38jklFv2& grant_type=authorization_code
Request example with Refresh Token (case 2):
POST /token HTTP/1.1 Host: https://op.spid.agid.gov.it Content-Type: application/x-www-form-urlencoded client_id=https://rp.spid.agid.gov.it& client_assertion=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiw ibmFtZSI6IlNQSUQiLCJhZG1pbiI6dHJ1ZX0.LVyRDPVJm0S9q7oiXcYVIIqGWY0wWQlqxvFGYswL…& client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwtbearer& grant_type=refresh_token& refresh_token=8xLOxBtZp8
Claim |
Description |
Supported by |
---|---|---|
client_id |
See OpenID.Registration. It MUST contain an HTTPS URL that uniquely identifies the RP. |
|
client_assertion |
JWT signed with the Relying Party's private key containing the following parameters:
|
|
client_assertion_type |
It must get the following value: |
|
code |
Authorization code returned in the Authentication Response. Required only if grant_type is authorization_code. |
|
code_verifier |
Verification code of the code_challenge. Required only if grant_type is authorization_code. |
|
grant_type |
Type of credentials, presented by the RP, for the current request. It MAY get one of the following values:
|
|
refresh_token |
Required only if grant_type is refresh_token. |
Response¶
The OpenID Provider (OP) returns an ID Token, an Access Token and possibly a Refresh Token.
The Access Token must be formed according to the standard indications of the "International Government Assurance Profile (iGov) for OAuth 2.0 - Draft 03", section 3.2.1, "JWT Bearer Tokens".
The ID Token must be formed according to the indications contained in the next section.
The response MUST contain the following claims.
Response example:
HTTP/1.1 200 OK
Last-Modified: Wed, 22 Jul 2018 19:15:56 GMT
Content-Type: application/json
{
"access_token":"dC34Pf6kdG...",
"token_type":"Bearer",
"refresh_token":"wJ848BcyLP...",
"expires_in":1800,
"id_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY..."
}
Claim |
Description |
Supported by |
---|---|---|
access_token |
The Access Token, in signed JWT format, allows accessing the UserInfo Endpoint for obtaining the attributes. |
|
token_type |
Type of Access Token returned. It MUST always be equal to Bearer. |
|
refresh_token |
Available only in case of long revocable session. The Refresh Token MUST be a signed JWT format. It allows calling again the Token Endpoint for obtaining a new Access Token and a new ID Token. |
|
expires_in |
Expity time of the Access Token in seconds. |
|
id_token |
ID Token in JWT format (see next section). |
Access Token¶
The Access Token is a signed JSON Web Token (JWT) that allows access to the UserInfo endpoint to get user attributes.
Access Token header and payload example:
{
"alg": "RS256",
"kid": "dB67gL7ck3TFiIAf7N6_7SHvqk0MDYMEQcoGGlkUAAw",
"typ": "at+jwt"
}
.
{
"iss":"https://op.spid.agid.gov.it",
"sub": "9sd798asd98asui23hiuds89y798sfyg",
"aud": "https://op.spid.agid.gov.it/userinfo",
"client_id": "https://rp.spid.example.it",
"scope": "openid",
"jti": "9ea42af0-594c-4486-9602-8a1f8dde42d3",
"exp": 1656859559,
"iat": 1656857579
}
Claim |
Description |
Supported by |
---|---|---|
iss |
It MUST be an HTTPS URL that uniquely identifies the OP. The client MUST verify that this value matches the called OP. |
|
sub |
See OpenID.Core#SubjectIDTypes. It MUST be of type pairwise. |
|
client_id |
It MUST contain a HTTPS URL that uniquely identifies the RP. |
|
aud |
It MUST contain a list of Resource Servers referring to token consuming party. It MUST contain at least the UserInfo Endpoint. |
|
scope |
The OP SHOULD add the scope parameter as defined in RFC 9068 Section 2.2.3. It MUST match the value in the authentication request. |
|
iat |
UNIX Timestamp with the time of JWT issuance, coded as NumericDate as indicated in RFC 7519. |
|
exp |
UNIX Timestamp with the expiry time of the JWT, coded as NumericDate as indicated in RFC 7519. |
|
jti |
It MUST be a String in uuid4 format. Unique Token ID identifier that the RP MAY use to prevent reuse by rejecting the Token ID if already processed. |
|
nonce |
See OpenID.Core#AuthRequest. It MUST be a random string of at least 32 alphanumeric characters. This value MUST match the value sent by the RP in the authentication request. |
ID Token¶
The ID Token is a signed JSON Web Token (JWT) that contains information about the user that has executed the authentication. The RPs MUST validate the ID Token.
In this case the ID Token MUST be a nested signed and encrypted JWT containing the cty (Content-Type) parameter in the JOSE header configured to JWT (see RFC 7519#section-5.2).
The claims available in the ID Token are given below.
Example of header and payload of an ID Token:
{
"alg": "RS256",
"kid": "dB67gL7ck3TFiIAf7N6_7SHvqk0MDYMEQcoGGlkUAAw"
}
.
{
"iss":"https://op.spid.agid.gov.it/",
"sub":"9sd798asd98asui23hiuds89y798sfyg",
"aud":"https://rp.spid.agid.gov.it/auth",
"acr":"https://www.spid.gov.it/SpidL2",
"at_hash":"qiyh4XPJGsOZ2MEAyLkfWqeQ",
"iat":1519032969,
"nbf":1519032969,
"exp":1519033149,
"jti":"nw4J0zMwRk4kRbQ53G7z",
"nonce":"MBzGqyf9QytD28eupyWhSqMj78WNqpc2"
}
Claim |
Description |
Supported by |
---|---|---|
iss |
It MUST be an HTTPS URL that uniquely identifies the OP. The client MUST verify that this value matches the called OP. |
|
sub |
See OpenID.Core#SubjectIDTypes. It MUST be pairwise type. |
|
aud |
It MUST match the value client_id. The RP MUST verify that this value matches its client ID. |
|
acr |
Effective authentication level. It MUST be equal or greater than the one requested by the client in the Authentication Request. |
|
at_hash |
See OpenID.Core#CodeIDToken. Its value is the base64url encoding of the left-most half of the hash of the octets of the ASCII representation of the Access Token value, where the hash algorithm used is the hash algorithm used in the alg Header Parameter of the ID Token's JOSE Header. The client MUST verify this value by applying the same function to the Access Token returned with the Token ID. |
|
iat |
UNIX Timestamp with the time of JWT issuance, coded as NumericDate as indicated in RFC 7519. |
|
nbf |
UNIX Timestamp. Time of the validity beginning of the JWT in NumericDate format, as indicated in RFC 7519. MUST match with the value of iat. |
|
exp |
UNIX Timestamp with the expiry time of the JWT, coded as NumericDate as indicated in RFC 7519. |
|
jti |
It MUST be a String in uuid4 format. Unique Token ID identifier that the RP MAY use to prevent reuse by rejecting the Token ID if already processed. |
|
nonce |
See OpenID.Core#AuthRequest. It MUST be a random string of at least 32 alphanumeric characters. This value MUST match the value sent by the RP in the authentication request. |
Refresh Token¶
The Refresh Token is a signed JWT that MAY be issued by the OP and MAY be used to obtain a new Access Token that enables the RP to access the UserInfo endpoint without requiring any direct user interaction.
The Refresh Token MUST be a signed JWT containing at least the following parameters.
Claim |
Description |
Supported by |
---|---|---|
iss |
It MUST be an HTTPS URL that uniquely identifies the OP. The RP MUST verify that this value matches the called OP. |
|
client_id |
It MUST match the value client_id. The RP MUST verify that this value matches its client ID. |
|
aud |
It MUST contain the OP Token Endpoint. |
|
iat |
UNIX Timestamp with the time of JWT issuance, coded as NumericDate as indicated in RFC 7519. |
|
exp |
UNIX Timestamp with the expiry time of the JWT, coded as NumericDate as indicated in RFC 7519. |
|
jti |
It MUST be a String in uuid4 format. Unique Refresh Token identifier that the RP MAY use to prevent reuse by rejecting the Refresh Token if already processed. |
Validity Period of a Refresh Token¶
The Refresh Token MUST NOT be valid (difference between iat and exp) more than 30 days.
If the Refresh Token is not valid (expired or revoked) and the RP sends a Token refresh request to the OP, the OP MUST return an error in the response (see Error codes).
Note
In order to clarify the rotation mechanism, a non-normative example is given below where Refresh Tokens are assumed to be valid for 30 days.
t1: an RP authenticates with scope=offline_access, then obtains a Refresh Token RT1 (validity 30gg)
t2 = t1 + 4gg: the RP makes a request to the Token endpoint by presenting RT1. The OP recognizes that the request is from the same RP and issues a new Access Token and new Refresh Token RT2 with validity 30gg from t2
t3 = t1 + 32gg: after 28gg from t2 the RP makes a request to the Token endpoint by submitting RT2. The OP recognizes that the request is from the same RP and issues a new Access Token and new Refresh Token RT3 with validity 30gg from t3
t4 = t1 + 64gg: after 32gg from t3 the RP makes a request to the Token endpoint by submitting RT3. This time the OP rejects the request with an error because RT3 is found to be no longer valid.
Error codes¶
Claim |
Description |
HTTP Code |
Supported by |
---|---|---|---|
invalid_client |
Client authentication failed (e.g., unknown client_id, no client authentication included, or unsupported authentication method) |
401 Unauthorized |
|
unsupported_grant_type |
The grant_type parameter contains an incorrect value. |
400 Bad Request |
|
invalid_grant |
The grant_type, code, code_verifier, access_token parameters are not valid. |
400 Bad Request |
|
invalid_request |
The request is not valid due to the lack or incorrectness of one or more parameters. |
400 Bad Request |
|
server_error |
The OP encountered an internal problem. |
500 internal server error |
|
temporarily_unavailable |
The OP encountered a temporary internal problem. |
503 Service Unavailable |