# Log in an employee

This how-to guides you through the steps required to ensure that only employees authenticated with [Entra ID](/auth/entra-id.md) can access your application.

## Prerequisites

Before you begin, ensure that you have:

- Familiarized yourselves with [the login proxy concepts](/auth/explanations.md#login-proxy).
- [Exposed your application with an ingress](/workloads/application/how-to/expose.md).

## Configure your application

Enable the login proxy for Entra ID in your application configuration:

```yaml
spec:
  azure:
    application:
      enabled: true
    sidecar:
      enabled: true
```

> **Login proxy is only available in GCP**
> Login proxy is only available in GCP clusters, and will not work in on-prem clusters.

See the [Nais application reference](/workloads/application/reference/spec.md#azuresidecar) for the complete specifications with all possible options.

### Grant access to users

When performing logins, end-users are redirected to Entra ID to authenticate themselves.
After logging in, Entra ID will check that the user is authorized to access your API application.
Unauthorized users are stopped in Entra ID during the login flow.

Consumer applications acting on behalf of a user may also request tokens from Entra ID that targets your API application.
Before issuing a token, Entra ID will check that the user is authorized to access your API application.

Users are not authorized by default.
To authorize users, specify access for either [specific groups](#groups), [all users](#all-users), or [both](#groups-and-all-users).

#### Groups

To authorize users that belong to a specific set of groups, you must do two things:

- specify the [group identifiers](/auth/entra-id/explanations.md#group-identifier). To find your group's identifier, see [finding the group identifier](/auth/entra-id/explanations.md#finding-the-group-identifier).
- set the `allowAllUsers` property to `false`

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

Only *direct* members of the specified groups are authorized.
Transitive membership through nested groups is not supported.

[The `groups` claim](/auth/entra-id/reference.md#claims:~:text=groups) in JWTs will include all matching group identifiers that the user is a direct member of.

> **Warning**
> Invalid group identifiers are skipped and will not be authorized to access the application in Entra ID.
> Ensure that the identifiers are correct and that the groups exist in Entra ID.

#### All users

To authorize *all* users, set the `allowAllUsers` property to `true`:

```yaml
spec:
  azure:
    application:
      enabled: true
      allowAllUsers: true
```

In practice, the property is equivalent to specifying a set of extra groups which covers all users in the Entra ID tenant.

[The `groups` claim](/auth/entra-id/reference.md#claims:~:text=groups) in JWTs will also include these extra groups that the user is a direct member of.

#### Groups and all users

You can also combine the above two configurations to authorize both specific groups and all users:

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

This has the following effects:

- All users are authorized to access your Entra ID application, i.e. through logins or on-behalf-of token requests.
- [The `groups` claim](/auth/entra-id/reference.md#claims:~:text=groups) in JWTs will include matching groups identifiers that the user is a direct member of.
  This also includes the extra groups added by the `allowAllUsers` property.

The combined configuration is useful if you want to authorize all users through Entra ID and
additionally use the `groups` claim in your application code to implement custom authorization logic.

## Handle inbound requests

Now that your application is configured, you will need to handle inbound requests in your application code.
As long as the user is authenticated, all requests to your application at the server-side will include the `Authorization` header with the user's `access_token` as a [Bearer token](/auth/explanations.md#bearer-token).

Your application is responsible for verifying that this token is present and valid. To do so, follow these steps:

### Handle missing or empty `Authorization` header

If the `Authorization` header is missing or empty, the employee is unauthenticated.

Return an appropriate HTTP status code to the frontend, and redirect the employee's user agent to the [login endpoint](/auth/reference.md#login-endpoint):

```
https://<ingress>/oauth2/login
```

### Validate token in `Authorization` header

If the `Authorization` header is present, validate the [JWT Bearer token](/auth/explanations.md#bearer-token) within.
If invalid, redirect the employee to the [login endpoint](/auth/reference.md#login-endpoint):

```
https://<ingress>/oauth2/login
```

> **Library for token validation**
> For JavaScript-based applications, we recommend using [navikt/oasis](https://github.com/navikt/oasis).
> This provides native utilities for validating tokens as well as [exchanging these for new tokens when consuming other APIs](#next-steps).

> Otherwise, you can implement validation with the steps below.

The steps below describe how to validate a token using the *token introspection endpoint*.

> **What is the token introspection endpoint?**
> The token introspection endpoint simplifies the token validation process, but does require a network call.

> If your application uses a library or framework that supports validering JWTs, you can alternatively let these handle the validation instead.
> See [the reference page for manually validating tokens](/auth/entra-id/reference.md#manual-token-validation).

Send a HTTP POST request to the endpoint found in the `NAIS_TOKEN_INTROSPECTION_ENDPOINT` environment variable.
The request must have a `Content-Type` header set to either:

- `application/json` or
- `application/x-www-form-urlencoded`

The body of the request should contain the following parameters:

| Parameter | Example Value | Description |
| :--- | :--- | :--- |
| `identity_provider` | `entra_id` | Always `entra_id`. |
| `token` | `eyJra...` | The access token you wish to validate. |

**application/json**

```http
POST ${NAIS_TOKEN_INTROSPECTION_ENDPOINT} HTTP/1.1
Content-Type: application/json

{
    "identity_provider": "entra_id",
    "token": "eyJra..."
}
```

**application/x-www-form-urlencoded**

```http
POST ${NAIS_TOKEN_INTROSPECTION_ENDPOINT} HTTP/1.1
Content-Type: application/x-www-form-urlencoded

identity_provider=entra_id&
token=eyJra...
```

The response is always a HTTP 200 OK response with a JSON body.

It always contains the `active` field, which is a boolean value that indicates whether the token is valid or not.

##### Success response

If the token is valid, the response will additionally contain **all** the token's claims:

```json
{
    "active": true,
    "exp": 1730980893,
    "iat": 1730977293,
    ...
}
```

Claims are copied verbatim from the token to the response.

> **Which claims are validated by the endpoint?**
> The endpoint only validates the token's signature and its [standard claims](/auth/explanations.md#claims-validation).

> [Other claims](/auth/entra-id/reference.md#claims) are included in the response, but are not validated.
> Your application must validate these other claims according to your own requirements.

##### Error response

If the token is invalid, the only additional field in the response is the `error` field:

```json
{
    "active": false,
    "error": "token is expired"
}
```

The `error` field contains a human-readable error message that describes why the token is invalid.

## Next steps

The employee is now authenticated and can access your application.
You can extract [the claims](/auth/entra-id/reference.md#claims) from the subject token found in the `Authorization` header to assert the user's identity.

However, the token is **only valid for *your* application**.
To consume other APIs on behalf of the employee, [exchange the token for a new token that targets a specific API](/auth/entra-id/how-to/consume-obo.md).

## Related pages

🎯 Learn how to [consume other APIs on behalf of a employee](/auth/entra-id/how-to/consume-obo.md)

📚 [Entra ID reference](/auth/entra-id/reference.md)

📚 [Login proxy reference](/auth/reference.md#login-proxy)
