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>"

where each group is specified by their unique identifier.

To find your group's identifier, see finding the 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

Groups and all users

If you want to implement custom group-based authorization logic in your application, combine the above two configurations:

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

This has the following effects:

  • All users will have access to your application
  • If a given user is a direct member of any matching group, the group's identifier will be emitted in the groups claim.

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.

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

Example configuration
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 (machine-to-machine calls).

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

Example configuration
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)

Human-readable client name of the consumer application that requested the token. This complements the client ID found in the azp claim and is intended for display purposes only.

Not guaranteed to be unique. Should not be used for authorization.

groups

JSON array of group identifiers that the user is a member of:

{
  "groups": [
    "43451d82-19cd-4828-918d-cbf7d5b572ec",
    "8f0bd3b2-9d3d-4f27-8543-5938db3e6a3e",
    "2d7..."
  ]
}

Used to implement group-based authorization logic in your application.

Only appears in flows where an end-user is involved, i.e. either login or on-behalf-of.

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.

A token is a machine-to-machine token if and only if this claim exists and has the value equal to app.

NAVident

Internal identifier for the employees in NAV.

Only appears in flows where an end-user is involved, i.e. either login or on-behalf-of.

roles

JSON array of roles that the application has access to:

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

Only appears in 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"
}

Only appears in 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

The trygdeetaten.no tenant is used for development purposes. To log in to this tenant, you will need a separate account other than your personal NAV account.

There are two types of accounts you can use:

  1. Synthetic test accounts: Visit the IDA self-service portal. See the #ida channel on Slack for details.
  2. Personal account: Visit navikt/devuser-check and see the "FAQ" section. Otherwise, consult the #tech-azure channel on Slack.

See also .spec.azure.application.tenant.

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.