# Secure your API with Maskinporten

This how-to guides you through the steps required to secure your API using [Maskinporten](/auth/maskinporten.md):

## Prerequisites

- [Expose your application](/workloads/application/how-to/expose.md) to consumers at a publicly accessible domain.

## Define scopes

A *scope* represents a permission that a given consumer has access to.

Declare all the scopes that you want to expose in your application's Nais manifest:

```yaml
spec:
  maskinporten:
    enabled: true
    scopes:
      exposes:
        # nav:helse/sykepenger/afp.write
        - enabled: true
          product: "helse"
          separator: "/"
          name: "sykepenger/afp.write"
        # nav:helse/sykepenger/afp.read
        - enabled: true
          product: "helse"
          separator: "/"
          name: "sykepenger/afp.read"
```

See the [fully qualified scope reference](/auth/maskinporten/reference.md#fully-qualified-scopes) for details on naming scopes.

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

## Grant access to consumers

Grant the external consumer access to the scopes by specifying their organization number:

```yaml
spec:
  maskinporten:
    enabled: true
    scopes:
      exposes:
        - name: "sykepenger/afp.read"
          enabled: true
          product: "helse"
          separator: "/"
          consumers:
            - orgno: "123456789"
```

Now that you have configured the scopes in Maskinporten, consumers can request tokens with these scopes.
You will need to validate these tokens in your application.

## Validate tokens

Verify incoming requests from consumers by validating the [JWT Bearer token](/auth/explanations.md#bearer-token) in the `Authorization` header.

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/maskinporten/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` | `maskinporten` | Always `maskinporten`. |
| `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": "maskinporten",
    "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=maskinporten&
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/maskinporten/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.

### Validate scopes

Your application must validate the `scope` claim in the token.

The `scope` claim is a string that contains a whitespace-separated list of scopes, for example:

```json
{
    "scope": "nav:helse/sykepenger/afp.read nav:helse/sykepenger/afp.write"
}
```

Validate that the `scope` claim contains the expected scope(s).

The semantics and authorization that a scope represents is up to you to define and enforce in your application code.
