Skip to content

Entra ID reference

Access policies

Applications

By default, no applications have access to your API. You must explicitly grant access to consumer applications.

app.yaml
spec:
  accessPolicy:
    inbound:
      rules:
        - application: app-a

        - application: app-b
          namespace: other-namespace

        - application: app-c
          namespace: other-namespace
          cluster: other-cluster

The above configuration authorizes the following applications:

  • application app-a running in the same namespace and same cluster as your application
  • application app-b running in the namespace other-namespace in the same cluster
  • application app-c running in the namespace other-namespace in the cluster other-cluster

Users

By default, no users have access to your application. You must explicitly grant access to either specific groups, all users, or both.

Groups

The following configuration only grants users that are direct members of the specified groups access to your application:

app.yaml
spec:
  azure:
    application:
      enabled: true
      allowAllUsers: false
      claims:
        groups:
          - id: "<group identifier>"

Warning

Invalid group identifiers are skipped and will not be granted access to your application. Ensure that they are correct and exist in Entra ID.

All users

The following configuration grants all users access your application:

app.yaml
spec:
  azure:
    application:
      enabled: true
      allowAllUsers: true

Fine-grained permissions

You may define custom permissions for your application in Entra ID and grant them to other consumer applications. Permissions will appear as claims in the consumer's token. Your application can then use these claims to implement custom authorization logic.

Warning

Custom permissions only apply in the context of your own application. They are not global permissions.

All the following conditions must be met for the custom permission to appear:

  1. The token is acquired by a consumer of your application.
  2. The consumer has been granted a custom permission in your access policy definition.
  3. The target audience is your application.

Custom scopes

A scope only applies to tokens acquired on behalf of an employee (service-to-service calls on behalf of an end-user).

Applications defined in the access policy are always assigned the default scope named defaultaccess.

Grant scopes to consumers by specifying the following:

spec:
  accessPolicy:
    inbound:
      rules:
        - application: app-a
          namespace: other-namespace
          cluster: other-cluster
          permissions:
            scopes:
              - "custom-scope"

The above configuration grants the application app-a the scope custom-scope.

Scopes will appear as a space separated string in the scp claim within the user's token.

Example decoded on-behalf-of token (click to expand)
{
  "aud": "8a5...",
  "iss": "https://login.microsoftonline.com/.../v2.0",
  "iat": 1624957183,
  "nbf": 1624957183,
  "exp": 1624961081,
  "aio": "AXQ...",
  "azp": "e37...",
  "azpacr": "1",
  "groups": [
    "2d7..."
  ],
  "name": "Navnesen, Navn",
  "oid": "15c...",
  "preferred_username": "Navn.Navnesen@nav.no",
  "rh": "0.AS...",
  "scp": "custom-scope defaultaccess",
  "sub": "6OC...",
  "tid": "623...",
  "uti": "i03...",
  "ver": "2.0"
}

Custom roles

A role only applies to tokens acquired as an application (service-to-service calls).

Applications defined in the access policy are always assigned the default role named access_as_application.

Grant roles to consumers by specifying the following:

spec:
  accessPolicy:
    inbound:
      rules:
        - application: app-a
          namespace: other-namespace
          cluster: other-cluster
          permissions:
            roles:
              - "custom-role"

The above configuration grants the application app-a the role custom-role.

Roles will appear in the roles claim as an array of strings within the application's token.

Example decoded client credentials token (click to expand)
{
  "aud": "8a5...",
  "iss": "https://login.microsoftonline.com/.../v2.0",
  "iat": 1624957347,
  "nbf": 1624957347,
  "exp": 1624961247,
  "aio": "E2Z...",
  "azp": "e37...",
  "azpacr": "1",
  "oid": "933...",
  "rh": "0.AS...",
  "roles": [
    "access_as_application",
    "custom-role"
  ],
  "sub": "933...",
  "tid": "623...",
  "uti": "kbG...",
  "ver": "2.0"
}

Claims

Notable claims in tokens from Entra ID:

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

JSON array of group identifiers that the user is a member of. Used to implement group-based authorization logic in your application.

This claim only applies in flows where a user is involved i.e., either the login or on-behalf-of flows. In order for a group to appear in the claim, all the following conditions must be true:

idtyp (identity type)

This is a special claim used to determine whether a token is a machine-to-machine (app-only) token or a on-behalf-of (user) token.

Tokens are a machine-to-machine tokens only if this claim exists and has the value app.

NAVident

The internal identifier for the employees in NAV. Only applies in flows where a user is involved i.e., either the login or on-behalf-of flows.

roles

The value of this claim is an array of strings that lists the roles that the application has access to:

{
  "roles": [
    "access_as_application",
    "role-a",
    "role-b"
  ]
}

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 them custom roles.

scp (scope)

The value of this claim is a space-separated string that lists the scopes that the application has access to:

{
   "scp": "defaultaccess scope1 scope2"
}

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 them custom scopes.

For a complete list of claims, see the Access Token Claims Reference in Entra ID. We only use v2.0 tokens.

Runtime Variables & Credentials

Your application will automatically be injected with environment variables at runtime.

Variables for acquiring tokens

These variables are used to:

Name Description
AZURE_APP_CLIENT_ID Client ID that uniquely identifies the application in Entra ID.
AZURE_APP_CLIENT_SECRET Client secret for the application in Entra ID.
AZURE_APP_WELL_KNOWN_URL The well-known URL for the metadata discovery document.
AZURE_OPENID_CONFIG_TOKEN_ENDPOINT token_endpoint from the metadata discovery document.

AZURE_APP_WELL_KNOWN_URL is optional if you're using AZURE_OPENID_CONFIG_TOKEN_ENDPOINT directly.

Variables for validating tokens

These variables are used to 🎯 secure your API:

Name Description
AZURE_APP_CLIENT_ID Client ID that uniquely identifies the application in Entra ID.
AZURE_APP_WELL_KNOWN_URL The well-known URL for the metadata discovery document.
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 is optional if you're using AZURE_OPENID_CONFIG_ISSUER and AZURE_OPENID_CONFIG_JWKS_URI directly.

Spec

For all possible configuration options, see the 📚 NAIS application reference.

Tenants

Available tenants in Entra ID. NAV has two tenants in Entra ID:

Tenant Name Description
nav.no Production tenant
trygdeetaten.no Development tenant

Logging into the trygdeetaten.no tenant

See https://github.com/navikt/devuser-check/blob/main/README.md#faq for instructions on acquiring a user and logging into this tenant. Otherwise, consult the #tech-azure Slack channel.

Troubleshooting

This section lists common problems and solutions.

Missing application access policy

Your application (named A in the examples below) attempts to consume another application (named B).

When requesting a token from Entra ID, your application may receive a 400 Bad Request with an invalid_grant error response and the following message:

AADSTS501051:

Application '<client ID>' (<cluster>:<namespace>:<A>) is not assigned to a role for the application 'api://<cluster>.<namespace>.<B>' (<cluster>:<namespace>:<B>)"

Or the other variant:

AADSTS65001:

The user or administrator has not consented to use the application with ID '<client ID>' named '<cluster>:<namespace>:<A>'.

Send an interactive authorization request for this user and resource.

Solution / Answer
  • Ensure that the scope value in your application's request follows the correct format:

    api://<cluster>.<namespace>.<application>/.default>

  • Ensure that application B's access policy includes application A.

  • If all else fails, request assistance in the #nais channel on Slack.

Missing user access policy

When attempting to sign-in or perform the on-behalf-of flow, an application may receive a 400 Bad Request with an invalid_grant error response and the following message:

AADSTS50105:

Your administrator has configured the application <cluster>:<namespace>:<A> ('<client id>') to block users unless they are specifically granted ('assigned') access to the application.

The signed in user '{EmailHidden}' is blocked because they are not a direct member of a group with access, nor had access directly assigned by an administrator.

Please contact your administrator to assign access to this application

Solution / Answer
  • Ensure that application A has configured user access.
  • Ensure that the given user is a direct member of any configured groups).
  • If all else fails, request assistance in the #nais channel on Slack.

Tenant mismatch for signed-in user

While attempting to log in, you may receive the following error message from Entra ID:

Selected user account does not exist in tenant 'some-tenant' and cannot access the application '<client-id>' in that tenant.

The account needs to be added as an external user in the tenant first.

Please use a different account.

Solution / Answer
  • Ensure that the user uses an account that matches your application's tenant when logging in.
  • If all else fails, request assistance in the #nais channel on Slack.