Skip to content

Commit

Permalink
auth/tokenx: rewrite to diataxis
Browse files Browse the repository at this point in the history
Co-authored-by: Johnny Horvi <johnny@horvi.no>
Co-authored-by: Trong Huu Nguyen <trong.huu.nguyen@nav.no>
  • Loading branch information
jhrv and tronghn committed May 22, 2024
1 parent 9fb430e commit 054fbb3
Show file tree
Hide file tree
Showing 20 changed files with 418 additions and 385 deletions.
1 change: 1 addition & 0 deletions docs/auth/.pages
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
nav:
- README.md
- 💡 Explanations: explanations
- 📚 Reference: reference
- ...
4 changes: 2 additions & 2 deletions docs/auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ NAIS helps your applications [log in users](#logging-in-users), [validate inboun

- [**TokenX**][TokenX]

Internal, for applications acting on-behalf-of ID-porten citizens.
For internal applications acting on-behalf-of ID-porten citizens.

- [**Maskinporten**][Maskinporten]

Expand Down Expand Up @@ -91,5 +91,5 @@ The graph above can also be described as:

[Azure AD]: ../security/auth/azure-ad/README.md
[ID-porten]: ../security/auth/idporten.md
[TokenX]: ../security/auth/tokenx.md
[TokenX]: tokenx/README.md
[Maskinporten]: maskinporten/README.md
10 changes: 5 additions & 5 deletions docs/auth/explanations/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ There are multiple ways of obtaining such a grant, depending on the use case:

**Citizen-facing applications**

- [On-behalf-of an end-user with TokenX](../../security/auth/tokenx.md)
- [On-behalf-of an end-user with TokenX](../tokenx/README.md)

### OpenID Connect

Expand Down Expand Up @@ -75,7 +75,7 @@ Providers that the platform supports provisioning for:
- [Azure AD](../../security/auth/azure-ad/README.md)
- [ID-porten](../../security/auth/idporten.md)
- [Maskinporten](../maskinporten/README.md)
- [TokenX](../../security/auth/tokenx.md)
- [TokenX](../tokenx/README.md)

#### Well-Known URL / Metadata Document

Expand Down Expand Up @@ -198,7 +198,7 @@ See the respective identity provider page for details:

- [Azure AD](../../security/auth/azure-ad/usage.md#runtime-variables-credentials)
- [ID-porten](../../security/auth/idporten.md#runtime-variables-credentials)
- [TokenX](../../security/auth/tokenx.md#runtime-variables-credentials)
- [TokenX](../tokenx/README.md#runtime-variables-credentials)

#### Client Authentication

Expand Down Expand Up @@ -428,7 +428,7 @@ Validation should always be performed before granting access to any [resource se
Use well-known and widely used libraries and frameworks that take care of most
of the heavy lifting for you.

See [libraries and frameworks](../../security/auth/development.md#libraries-and-frameworks) for a non-comprehensive list.
See [libraries and frameworks](../reference/README.md#libraries-and-frameworks-for-validating-and-acquiring-tokens) for a non-comprehensive list.

#### Signature Validation

Expand Down Expand Up @@ -472,7 +472,7 @@ See the individual identity provider pages for specific validation related to ea
- [Azure AD](../../security/auth/azure-ad/usage.md#token-validation)
- [ID-porten](../../security/auth/idporten.md#token-validation)
- [Maskinporten](../maskinporten/how-to/secure.md#validate-tokens)
- [TokenX](../../security/auth/tokenx.md#token-validation)
- [TokenX](../tokenx/README.md#token-validation)

---

Expand Down
32 changes: 16 additions & 16 deletions docs/auth/maskinporten/how-to/consume.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,22 @@ The client assertion is a JWT that consists of a **header**, a **payload** and a

The **header** should consist of the following parameters:

| Parameter | Value | Description |
|:----------|:-----------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`kid`** | `<kid-from-JWK>` | The key identifier of the [private JWK](../../explanations/README.md#private-keys) used to sign the assertion. The private key is found in the `MASKINPORTEN_CLIENT_JWK` [environment variable](../reference/README.md#runtime-variables-credentials). |
| **`typ`** | `JWT` | Represents the type of this JWT. Set this to `JWT`. |
| **`alg`** | `RS256` | Represents the cryptographic algorithm used to secure the JWT. Set this to `RS256`. |
| Parameter | Value | Description |
|:----------|:-----------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`kid`** | `<kid-from-JWK>` | The key identifier of the [private JWK](../../explanations/README.md#private-keys) used to sign the assertion. The private key is found in the `MASKINPORTEN_CLIENT_JWK` [environment variable][variables-ref]. |
| **`typ`** | `JWT` | Represents the type of this JWT. Set this to `JWT`. |
| **`alg`** | `RS256` | Represents the cryptographic algorithm used to secure the JWT. Set this to `RS256`. |

The **payload** should have the following claims:

| Claim | Example Value | Description |
|:------------|:---------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`aud`** | `https://test.maskinporten.no/` | The _audience_ of the token. Set this to the Maskinporten `issuer`, i.e. [`MASKINPORTEN_ISSUER`](../reference/README.md/#runtime-variables-credentials). |
| **`iss`** | `60dea49a-255b-48b5-b0c0-0974ac1c0b53` | The _issuer_ of the token. Set this to your `client_id`, i.e. [`MASKINPORTEN_CLIENT_ID`](../reference/README.md/#runtime-variables-credentials). |
| **`scope`** | `nav:test/api` | `scope` is a whitespace-separated list of scopes that you want in the issued token from Maskinporten. |
| **`iat`** | `1698435010` | `iat` stands for _issued at_. Timestamp (seconds after Epoch) for when the JWT was issued or created. |
| **`exp`** | `1698435070` | `exp` is the _expiration time_. Timestamp (seconds after Epoch) for when the JWT is no longer valid. This **must** be less than **120** seconds after `iat`. A lifetime between 10-30 seconds should be fine for most situations. |
| **`jti`** | `2d1a343c-6e7d-4ace-ae47-4e77bcb52db9` | The _JWT ID_ of the token. Used to uniquely identify a token. Set this to a unique value such as an UUID. |
| Claim | Example Value | Description |
|:------------|:---------------------------------------|:----------------------------------------------------------------------------------------------------------|
| **`aud`** | `https://test.maskinporten.no/` | The _audience_ of the token. Set to [`MASKINPORTEN_ISSUER`][variables-ref]. |
| **`iss`** | `60dea49a-255b-48b5-b0c0-0974ac1c0b53` | The _issuer_ of the token. Set to [`MASKINPORTEN_CLIENT_ID`][variables-ref]. |
| **`scope`** | `nav:test/api` | `scope` is a whitespace-separated list of scopes that you want in the issued token from Maskinporten. |
| **`iat`** | `1698435010` | `iat` stands for _issued at_. Set to now. |
| **`exp`** | `1698435070` | `exp` is the _expiration time_. Between 1 and 120 seconds after now. Typically 30 seconds is fine |
| **`jti`** | `2d1a343c-6e7d-4ace-ae47-4e77bcb52db9` | The _JWT ID_ of the token. Used to uniquely identify a token. Set this to a unique value such as an UUID. |

If the API provider requires the use of an [audience-restricted token](https://docs.digdir.no/maskinporten_func_audience_restricted_tokens.html), you must also include the following claim:

Expand Down Expand Up @@ -164,7 +164,7 @@ The body of the request should contain the following parameters:
| `grant_type` | `urn:ietf:params:oauth:grant-type:jwt-bearer` | Type of grant the client is sending. Always `urn:ietf:params:oauth:grant-type:jwt-bearer`. |
| `assertion` | `eyJraWQ...` | The client assertion itself. It should be unique and only used once. |

Send the request to the `token_endpoint`, i.e. [`MASKINPORTEN_TOKEN_ENDPOINT`](../reference/README.md#runtime-variables-credentials):
Send the request to the `token_endpoint`, i.e. [`MASKINPORTEN_TOKEN_ENDPOINT`][variables-ref]:

```http
POST ${MASKINPORTEN_TOKEN_ENDPOINT} HTTP/1.1
Expand All @@ -186,7 +186,7 @@ Maskinporten will respond with a JSON object that contains the access token.
}
```

???+ note "Cache your tokens!"
???+ note "Cache your tokens"

The `expires_in` field in the response indicates the lifetime of the token in seconds.

Expand All @@ -207,4 +207,4 @@ Host: api.example.com
Authorization: Bearer eyJraWQ...
```

Success!
[variables-ref]: ../reference/README.md#variables-for-acquiring-tokens
8 changes: 5 additions & 3 deletions docs/auth/maskinporten/how-to/secure.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ Additionally, perform the following validations:

Validate that the `iss` claim has a value that is equal to either:

1. the `MASKINPORTEN_ISSUER` [environment variable](#runtime-variables-credentials), or
1. the [`MASKINPORTEN_ISSUER`][variables-ref] environment variable, or
2. the `issuer` property from the [metadata discovery document](../../explanations/README.md#well-known-url-metadata-document).
The document is found at the endpoint pointed to by the `MASKINPORTEN_WELL_KNOWN_URL` environment variable.

Expand All @@ -90,13 +90,15 @@ The value must be an absolute URI (such as `https://some-provider.no` or `https:
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:

1. the `MASKINPORTEN_JWKS_URI` environment variable, or
1. the [`MASKINPORTEN_JWKS_URI`][variables-ref] environment variable, or
2. the `jwks_uri` property from the metadata discovery document.
The document is found at the endpoint pointed to by the `MASKINPORTEN_WELL_KNOWN_URL` environment variable.
The document is found at the endpoint pointed to by the [`MASKINPORTEN_WELL_KNOWN_URL`][variables-ref] environment variable.

**Other Token Claims**

Other claims may be present in the token.
Validation of these claims is optional.

See the [Access Token Reference in Maskinporten](https://docs.digdir.no/docs/Maskinporten/maskinporten_protocol_token#the-access-token) for a list of all claims.

[variables-ref]: ../reference/README.md#variables-for-validating-tokens
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
---
tags: [auth, explanation]
tags: [auth, reference]
---

# Development
# Auth reference

## Mocking
## Libraries for mocking

- <https://github.com/navikt/mock-oauth2-server>
- <https://github.com/navikt/fakedings> - a wrapper around the above mock server

## Libraries and Frameworks
## Libraries and frameworks for validating and acquiring tokens

Below is a list of some well-known and widely used libraries for handling OAuth, OpenID Connect, and token validation.

Expand All @@ -24,18 +24,17 @@ Below is a list of some well-known and widely used libraries for handling OAuth,
### JavaScript

- <https://github.com/navikt/oasis>
- <https://github.com/navikt/next-auth-wonderwall>
- <https://github.com/panva/jose>
- <https://github.com/panva/node-openid-client>

See also <https://jwt.io/libraries> for a non-comprehensive list for many various languages.
See also <https://jwt.io/libraries> for a non-comprehensive list for many other various languages.

## Token Generators

In many cases, you want to locally develop and test against a secured API in the development environments.
In some cases, you want to locally develop and test against a secured API in the development environments.
You will need a token to access said API.

See the respective identity provider pages for details on acquiring such tokens:

- [Azure AD](azure-ad/usage.md#token-generator)
- [TokenX](tokenx.md#token-generator)
- [Azure AD](../../security/auth/azure-ad/usage.md#token-generator)
- [TokenX](../tokenx/reference/README.md#token-generator)
6 changes: 6 additions & 0 deletions docs/auth/tokenx/.pages
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
title: TokenX
nav:
- README.md
- 🎯 How-To: how-to
- 📚 Reference: reference
- ...
41 changes: 41 additions & 0 deletions docs/auth/tokenx/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
tags: [auth, services]
---

# TokenX overview

TokenX is NAIS' own implementation of OAuth 2.0 Token Exchange.

This allows applications to act on behalf of a citizen that originally authenticated with ID-porten, while maintaining the [zero-trust](../../workloads/explanations/zero-trust.md) security model between applications throughout the request chain.

NAIS provides support for declarative registration and configuration of TokenX resources.
These cover two distinct use cases:

## Consume an API

To consume an API secured with TokenX on behalf of a citizen, you'll need to exchange the inbound [token](../explanations/README.md#tokens) for a new token.
The new token is only valid for the API you want to access and contains the citizens identity context.

```mermaid
graph LR
Consumer -->|1. citizen token| A
A["your app"] -->|2. exchange token| TokenX
TokenX -->|3. new token for other app| A
A -->|4. use token| O[other app]
```

:dart: Learn how to [consume a API using TokenX](how-to/consume.md)

## Secure your API

To secure your API with TokenX, you'll first need to grant access to your consumers.

```mermaid
graph LR
Provider["Application"] -->|grant access| TokenX
```

Once configured, your consumers can [exchange a token from TokenX](#consume-an-api) that targets your application.
Your application must then validate inbound requests from the consumer.

:dart: Learn how to [secure your API using TokenX](how-to/secure.md)
Loading

0 comments on commit 054fbb3

Please sign in to comment.