Accessing data using JWT Token Exchange
Data sources protected by Feide are normally configured in the customer portal. The customer portal is used to configure policies for access to data sources and access levels. The data are accessed using JSON Web Tokens (JWTs). The data consumer obtains an OpenID Connect (OIDC) access token. It exchanges it for another token tailored for the data source, carrying all information the source needs to determine what information the consumer may access. This token is a JWT. It is short lived and digitally signed, allowing the data source to verify that it was issued by Feide, intended for the source, and still valid. The exchange conforms to RFC 8693 - Oauth2 token exchange.
In order to access a data source, you need a Feide service registered in the customer portal. It may be a service that users log in to, or a headless service with no associated user. It needs an OpenID Connect configuration with rights to access the data source and the appropriate access levels within it.
The data owner must approve access to the data, unless they have chosen to make the data source public.
Access starts with an OIDC access token. This could be the token the service receives when the user logs in, or a token which a headless service obtains with the client credentials flow.
Next, the service presents the access token to Feide and, if successful, receives back a JWT token for the
data source. The request to Feide is a token exchange request to the
token endpoint. For this request, grant type urn:ietf:params:oauth:grant-type:token-exchange
is used.
The response from the token endpoint is a token exchange response, which,
unless the request fails, includes a JWT access token.
With each request to a data source endpoint, the service includes the JWT as a bearer token in the
Authorization
header. The data source verifies the signature of the token and checks that it is still
valid, issued by Feide and intended for the data source. Finally, it checks which access levels the token
authorizes, and responds appropriately.
Token exchange request
A token exchange request includes audience
and scope
parameters. The audience
must be the data source
UUID registered in the customer portal, prefixed by https://n.feide.no/datasources/
. Example:
https://n.feide.no/datasources/02d0f79b-7fbc-422b-bb31-a4d22121f040
. The valid values for scopes are the
identifiers of the access levels which are registered in the customer portal for the data source.
A token exchange request is made to the token endpoint using the HTTP “POST” method. Parameters are included in the
HTTP request entity-body using the application/x-www-form-urlencoded
format. The parameters are:
- audience
The UUID of the data source the JWT is intended for, prefixed by
https://n.feide.no/datasources/
.- client_id
The ID of the application making the exchange request.
- client_secret
The client secret of the application.
- grant_type
The value
urn:ietf:params:oauth:grant-type:token-exchange
selects Oauth2 token exchange.- scope
A space separated list of identifiers of desired access levels. It is up to the data source how to interpret them.
- subject_token
An access token obtained from Feide. It should give the application access to the access levels given as
scope
in the data source given asaudience
.- subject_token_type
Must be
urn:ietf:params:oauth:token-type:access_token
.
Here is an example:
POST https://auth.dataporten.no/oauth/token
content-type: application/x-www-form-urlencoded
audience=https://n.feide.no/datasources/02d0f79b-7fbc-422b-bb31-a4d22121f040
&client_id=208335d4-e8c1-4910-8928-05b2e5b14127
&client_secret=5df85658-d0c1-4348-890a-a204b24eca2e
&grant_type=urn:ietf:params:oauth:grant-type:token-exchange
&scope=read append
&subject_token=96c5a3aa-1af8-45bd-a4f8-4b7fb07d393f
&subject_token_type=urn:ietf:params:oauth:token-type:access_token
Successful response
A successful response has status 200 and an application/json
body with the following attributes:
- token_type
The type is
Bearer
.- issued_token_type
The type is
urn:ietf:params:oauth:token-type:jwt
.- access_token
The JWT that was issued.
- expires_in
Number of seconds until JWT expires.
- scope
The scopes that were granted.
Here is an example:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI...",
"token_type": "Bearer",
"issued_token_type": "urn:ietf:params:oauth:token-type:jwt",
"expires_in": 299,
"scope": "read append"
}
JWT access token
The token is an ASCII string. It is intended for a third party data source. It consists of a header, a payload
and a signature, with a .
between them. Each are base64url encoded. See
RFC 7519 - JSON Web Token (JWT). The payload is a json object
containing claims.
If the token authenticates a user, it may contain claims about the user. A claim is only included if the service that requested the token and the data source both are authorized to access the claim.
The following claims are always included in the token:
- aud
Audience. The data source should only accept the token if it is the intended audience.
- iss
Issuer. Value is
https://auth.dataporten.no
if token was issued by Feide.- iat
Time of issue. This and other time attributes are given in seconds since 1970-01-01T0:0:0 UTC.
- exp
Expiration time.
- nbf
Not valid before time. Protects against clock skew.
- client_id
ID of the application that requested the token.
- sub
Subject - the identity which the token authenticates. Can be a dataporten user ID or a client ID.
- scope
The scopes that were granted.
- act
Actor. It represents a chain of delegation. E.g., an application could authorize a data source to access another on its behalf. We do not currently support delegation in JWT tokens, so the chain is only one level deep. It is a json object with a single attribute:
sub
, with the same value asclient_id
in the token.
The following user claims may be included:
- name
Name of user who the token authenticates.
- picture
Picture of user.
- https://n.feide.no/claims/userid_sec
Secondary user ID of user.
- https://n.feide.no/claims/eduPersonPrincipalName
eduPersonPrincipalName of user. Only for users who authenticated to the Feide IDP.
- https://n.feide.no/claims/nin
Norwegian national identity number of user. Only for users who authenticated to ID-porten.
Here is an example of what the payload may look like after decoding:
{
"aud": "https://n.feide.no/datasources/02d0f79b-7fbc-422b-bb31-a4d22121f040",
"iss": "https://auth.dataporten.no",
"exp": 1610448035,
"iat": 1610447735,
"nbf": 1610447735,
"client_id": "208335d4-e8c1-4910-8928-05b2e5b14127",
"sub": "208335d4-e8c1-4910-8928-05b2e5b14127",
"scope": "read append",
"act": {
"sub": "208335d4-e8c1-4910-8928-05b2e5b14127",
}
}
Validating a JWT access token
The consumer must validate the access token. In particular, iss
has to be auth.dataporten.no
and aud
has to be the same as in the request. See
the JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens
for full details about JWT access token validation. Furthermore, the token is only valid if the current
time is in the interval between the iat
and exp
timestamps.
Token lifetimes
A JWT cannot be reliably revoked. Therefore, the lifetime is only 5 minutes. If the application needs access after the token has expired, it must obtain a new one.