Usage¶
Use Cases¶
An Azure AD client allows your application to leverage Azure AD for authentication and/or authorization. The following sections will describe the recommended flows and grants to be used for applications running on the platform.
OpenID Connect Authorization Code Flow¶
This flow is used for signing in and authenticating end-users (NAV employees only) with single-sign on (SSO).
graph LR
User --authenticate---> Application
Application --1. redirect to login---> AAD["Azure AD"]
AAD --2. redirect after login---> Application
We generally recommend that you use the sidecar instead of implementing this yourselves.
If you don't want to use the sidecar, see Microsoft identity platform and OAuth 2.0 authorization code flow for further details.
OAuth 2.0 On-Behalf-Of Grant¶
This grant is used for machine-to-machine requests chains initiated by an end user. The end user's identity and permissions should be propagated through each application.
graph LR
User --"request with subject token\n aud=Application"---> Application
Application --1. exchange subject token---> AAD["Azure AD"]
AAD --2. issue new token\n aud=Downstream API---> Application
Application --3. consume with new token\n aud=Downstream API---> Downstream["Downstream API"]
Your application receives requests from a user.
These requests contain the user's token, known as the subject token.
The token has an audience (aud
) claim equal to your own client ID.
In order to access a downstream API on-behalf-of the user, we need a token that is scoped to the downstream API. That is, the token's audience must be equal to the downstream API's client ID. We achieve this by exchanging the subject token for a new token.
The same principles apply if your application is a downstream API itself and needs to access another downstream API on-behalf-of the user.
Prerequisites
- Your application (also known as a resource server) and the downstream API that you want to consume both have enabled Azure AD.
- Your application has been granted access to the downstream API.
Steps
- Validate the subject token from the incoming request.
-
Request a new token that is scoped to the downstream API.
- Set the
scope
parameter toapi://<cluster>.<namespace>.<outbound-app-name>/.default
-
Request:
POST ${AZURE_OPENID_CONFIG_TOKEN_ENDPOINT} HTTP/1.1 Content-Type: application/x-www-form-urlencoded grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer &client_id=${AZURE_APP_CLIENT_ID} &client_secret=${AZURE_APP_CLIENT_SECRET} &assertion=<subject_token> &scope=api://<cluster>.<namespace>.<outbound-app-name>/.default &requested_token_use=on_behalf_of
-
Response (token omitted for brevity):
Token Caching
The
expires_in
field denotes the lifetime of the token in seconds.Cache and reuse the token until it expires to minimize network latency impact.
A safe cache key for on-behalf-of tokens is
key = sha256($subject_token + $scope)
. -
The new token has an audience equal to the downstream API. Your application does not need to validate this token.
- Set the
-
Consume the downstream API by using the new token as a Bearer token. The downstream API validates the token and returns a response.
- Repeat step 2 and 3 for each unique API that your application consumes.
- The downstream API(s) may continue the call chain starting from step 1.
For further details, see Microsoft identity platform and OAuth 2.0 On-Behalf-Of flow.
OAuth 2.0 Client Credentials Grant¶
This grant is used for pure machine-to-machine authentication, i.e. interactions without an end user involved.
graph LR
Application --1. request token---> AAD["Azure AD"]
AAD --2. issue token\n aud=Downstream API---> Application
Application --3. consume with token\n aud=Downstream API---> Downstream["Downstream API"]
In order to access a downstream API, we need a token that is scoped to the downstream API. That is, the token's audience must be equal to the downstream API's client ID.
Prerequisites
- Your application (also known as a resource server) and the downstream API that you want to consume both have enabled Azure AD.
- Your application has been granted access to the downstream API.
Steps
-
Request a new token that is scoped to the downstream API.
- Set the
scope
parameter toapi://<cluster>.<namespace>.<outbound-app-name>/.default
-
Request:
-
Response (token omitted for brevity):
Token Caching
The
expires_in
field denotes the lifetime of the token in seconds.Cache and reuse the token until it expires to minimize network latency impact.
A safe cache key for client credentials tokens is
key = $scope
. -
The new token has an audience equal to the downstream API. Your application does not need to validate this token.
- Set the
-
Consume downstream API by using the token as a Bearer token. The downstream API validates the token and returns a response.
- Repeat step 1 and 2 for each unique API that your application consumes.
- The downstream API(s) may continue the call chain by starting from step 1.
For further details, see Microsoft identity platform and the OAuth 2.0 client credentials flow.
Runtime Variables & Credentials¶
Your application will automatically be injected with both environment variables and files at runtime. You can use whichever is most convenient for your application.
The files are available at the following path: /var/run/secrets/nais.io/azure/
Variables for Acquiring Tokens¶
These variables are used for acquiring tokens using the client credentials grant or the on-behalf-of grant:
Name | Description |
---|---|
AZURE_APP_CLIENT_ID |
Client ID that uniquely identifies the application in Azure AD. |
AZURE_APP_CLIENT_SECRET |
Client secret for the application in Azure AD. |
AZURE_APP_JWK |
Optional. Private JWK (RSA) for the application. |
AZURE_OPENID_CONFIG_TOKEN_ENDPOINT |
token_endpoint from the metadata discovery document. |
AZURE_APP_WELL_KNOWN_URL |
The well-known URL for the metadata discovery document. |
AZURE_APP_WELL_KNOWN_URL
is optional if you're using AZURE_OPENID_CONFIG_TOKEN_ENDPOINT
directly.
AZURE_APP_JWK
contains a private key that can be used to sign JWT client assertions.
This is an alternative client authentication method that can be used instead of client secrets.
For further details, see Microsoft's documentation on certificate credentials.
The aud
claim in the JWT assertions should be set to the value of the AZURE_OPENID_CONFIG_TOKEN_ENDPOINT
environment variable.
Variables for Validating Tokens¶
These variables are used for token validation:
Name | Description |
---|---|
AZURE_APP_CLIENT_ID |
Client ID that uniquely identifies the application in Azure AD. |
AZURE_OPENID_CONFIG_ISSUER |
issuer from the metadata discovery document. |
AZURE_OPENID_CONFIG_JWKS_URI |
jwks_uri from the metadata discovery document. |
AZURE_APP_WELL_KNOWN_URL |
The well-known URL for the metadata discovery document. |
AZURE_APP_WELL_KNOWN_URL
is optional if you're using AZURE_OPENID_CONFIG_ISSUER
and AZURE_OPENID_CONFIG_JWKS_URI
directly.
Token Validation¶
Verify incoming requests by validating the Bearer token in the Authorization
header.
Always validate the signature and standard time-related claims. Additionally, perform the following validations:
Issuer Validation
Validate that the iss
claim has a value that is equal to either:
- the
AZURE_OPENID_CONFIG_ISSUER
environment variable, or - the
issuer
property from the metadata discovery document. The document is found at the endpoint pointed to by theAZURE_APP_WELL_KNOWN_URL
environment variable.
Audience Validation
Validate that the aud
claim is equal to the AZURE_APP_CLIENT_ID
environment variable.
Signature Validation
Validate that the token is signed with a public key published at the JWKS endpoint. This endpoint URI can be found in one of two ways:
- the
AZURE_OPENID_CONFIG_JWKS_URI
environment variable, or - the
jwks_uri
property in the metadata discovery document. The document is found at the endpoint pointed to by theAZURE_APP_WELL_KNOWN_URL
environment variable.
Other Token Claims¶
Other claims may be present in the token. Validation of these claims is optional.
Notable claims:
azp
(authorized party)- The client ID of the application that requested the token (this would be your consumer).
azp_name
(authorized party name)- The value of this claim is the (human-readable) name of the consumer application that requested the token.
groups
(groups)- JSON array of object IDs for Azure AD groups.
- This claim only applies in flows where a user is involved i.e., either the sign-in or on-behalf-of flows.
- In order for a group to appear in the claim, all the following conditions must be true:
- The given user is a direct member of the group.
- The group is assigned to the client.
idtyp
(identity type)- This is a special claim used to determine whether a token is a machine-to-machine (app-only) token or a user/on-behalf-of token.
- The claim currently only appears in machine-to-machine tokens. The value is
app
when the token is a machine-to-machine token. - In short: if the
idtyp
claim exists and it has the valueapp
, then it is a machine-to-machine token. Otherwise, it is a user/on-behalf-of token.
NAVident
(NAV ident)- The value of this claim maps to an internal identifier for the employees in NAV.
- This claim thus only applies in flows where a user is involved i.e., either the sign-in or on-behalf-of flows.
roles
(roles)- The value of this claim is an array of strings that lists the roles that the application has access to:
- This claim only applies to machine-to-machine tokens.
- Consumers defined in the access policy are always assigned the default role named
access_as_application
. - You can optionally define and grant additional custom roles to consumers.
scp
(scope)- The value of this claim is a space-separated string that lists the scopes that the application has access to:
- This claim only applies to user or on-behalf-of tokens.
- Consumers defined in the access policy are always assigned the default scope named
defaultaccess
. - You can optionally define and grant additional custom scopes to consumers.
For a complete list of claims, see the Access Token Claims Reference in Azure AD. Tokens in NAV are v2.0 tokens.
Local Development¶
See also the development overview page.
Token Generator¶
In many cases, you want to locally develop and test against a secured API (or resource server) in the development environments. To do so, you need a token in order to access said API.
The service https://azure-token-generator.intern.dev.nav.no can be used in order to generate tokens in the development environments.
Prerequisites
- The API application must be configured with Azure enabled. Using the
nav.no
tenant is not supported. - You will need a trygdeetaten.no user in order to access the service.
- Pre-authorize the token generator service by adding it to the API application's access policy:
- Ensure that the API application has configured the appropriate user access policies that grant your user access.
Getting a token
The Azure AD token generator supports two use cases:
- The on-behalf-of grant - for getting a token on-behalf-of a logged in end-user.
- The client credentials grant - for getting a machine-to-machine token.
Choose your use case:
- For on-behalf-of: visit https://azure-token-generator.intern.dev.nav.no/api/obo?aud=<audience> in your browser.
- For client credentials: visit https://azure-token-generator.intern.dev.nav.no/api/m2m?aud=<audience> in your browser.
Then:
- Replace
<audience>
with the intended audience of the token, in this case the API application.- The audience value must be on the form of
<cluster>:<namespace>:<application>
- For example:
dev-gcp:aura:my-app
- The audience value must be on the form of
- You will be redirected to log in at Azure AD (if not already logged in).
- After logging in, you should be redirected back to the token generator and presented with a JSON response containing an
access_token
. - Use the
access_token
as a Bearer token for calls to your API application. - Success!
Test Clients¶
If mocking isn't sufficient, we also maintain some test clients for use in local development environments.
Note that the associated credentials may be rotated at any time.
As developers, you're responsible for treating these credentials as secrets. Never commit or distribute these to version control or expose them to publicly accessible services.
Credentials are found in Vault under /secrets/secret/.common/azure
The clients are configured with the following redirect URIs:
http://localhost:3000/oauth2/callback
The clients are pre-authorized as follows:
test-app-1
is pre-authorized fortest-app-2
test-app-2
is pre-authorized fortest-app-3
They are otherwise equal to a default client.
Created: 2021-07-08