# OIDC4IA ID Token

The ID token returned by DIP follows the OIDC4IA (OpenID Connect for Identity Assurance) specification. It contains verified identity claims with evidence of how the identity was verified.

## Token Format

The ID token is returned as an **encrypted JWT (JWE)** containing a **signed JWT**.

| Layer | Format     | Algorithm                     |
| ----- | ---------- | ----------------------------- |
| Outer | JWE        | `RSA-OAEP-256` with `A256GCM` |
| Inner | Signed JWT | `ES256`                       |

## Complete Token Structure

After decryption and signature verification:

```json
{
  "iss": "https://{dip-base-url}",
  "sub": "pairwise-hashed-subject-identifier",
  "aud": "dip_aci_your_client_id",
  "exp": 1759839472,
  "iat": 1759835872,
  "auth_time": 1759835872,
  "jti": "e29b7c1e-6b4a-4a3b-9b1a-2f6c8a7d5e10",
  "nonce": "n-0S6_WzA2Mj",
  "acr": "urn:bankid:idcheck",
  "amr": ["face", "user"],
  "verified_claims": {
    "verification": {
      "trust_framework": "stoe",
      "evidence": [
        {
          "type": "document",
          "document_details": {
            "type": "passport",
            "document_number": "AB1234567",
            "date_of_issuance": "2020-01-15",
            "date_of_expiry": "2030-01-15",
            "issuer": {
              "country_code": "NOR",
              "name": "INNLANDET POLITIDISTRIKT"
            },
            "personal_number": "12345678901"
          },
          "check_details": [
            {
              "check_method": "vcrypt",
              "result": "success"
            },
            {
              "check_method": "data",
              "organization": "id.politiet.no",
              "time": "2024-01-15T10:30:00Z",
              "result": "valid"
            }
          ]
        }
      ]
    },
    "claims": {
      "given_name": "AASAMUND SPECIMEN",
      "family_name": "OESTENBYEN",
      "picture": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
      "birthdate": "1990-01-15",
      "gender": "male",
      "nationalities": ["NOR"]
    }
  }
}
```

## Standard OIDC Claims

These claims are always present in the ID token:

| Claim       | Type      | Required | Description                                                                                     |
| ----------- | --------- | -------- | ----------------------------------------------------------------------------------------------- |
| `iss`       | string    | Yes      | Issuer identifier (DIP base URL)                                                                |
| `sub`       | string    | Yes      | Pairwise subject identifier (unique per client)                                                 |
| `aud`       | string    | Yes      | Audience (your `client_id`)                                                                     |
| `exp`       | number    | Yes      | Expiration time (Unix timestamp)                                                                |
| `iat`       | number    | Yes      | Issued at time (Unix timestamp)                                                                 |
| `auth_time` | number    | Yes      | Time of authentication (Unix timestamp)                                                         |
| `jti`       | string    | Yes      | Unique identifier for this token (JWT ID). Can be used to detect replay or duplicate processing |
| `nonce`     | string    | Yes      | Nonce from authorization request                                                                |
| `acr`       | string    | Yes      | Authentication Context Class Reference                                                          |
| `amr`       | string\[] | Yes      | Authentication Methods References                                                               |

### Example Standard Claims

```json
{
  "iss": "https://{dip-base-url}",
  "sub": "a1b2c3d4e5f6g7h8i9j0",
  "aud": "dip_aci_your_client_id",
  "exp": 1759839472,
  "iat": 1759835872,
  "auth_time": 1759835872,
  "jti": "e29b7c1e-6b4a-4a3b-9b1a-2f6c8a7d5e10",
  "nonce": "n-0S6_WzA2Mj",
  "acr": "urn:bankid:idcheck",
  "amr": ["face", "user"]
}
```

### ACR Values

| Value                | Description                                           |
| -------------------- | ----------------------------------------------------- |
| `urn:bankid:idcheck` | Identity verified via document and facial recognition |

### AMR Values

| Value  | Description                  |
| ------ | ---------------------------- |
| `face` | Facial recognition performed |
| `user` | User interaction completed   |

## Verified Claims Structure

The `verified_claims` object contains identity data with verification evidence.

### Top-Level Structure

```json
{
  "verified_claims": {
    "verification": { ... },
    "claims": { ... }
  }
}
```

| Field          | Type   | Description                   |
| -------------- | ------ | ----------------------------- |
| `verification` | object | How the identity was verified |
| `claims`       | object | The verified identity claims  |

## Verification Object

The `verification` object describes the trust framework and evidence used.

```json
{
  "verification": {
    "trust_framework": "stoe",
    "evidence": [ ... ]
  }
}
```

| Field             | Type   | Description                |
| ----------------- | ------ | -------------------------- |
| `trust_framework` | string | Trust framework identifier |
| `evidence`        | array  | List of evidence objects   |

### Trust Framework Values

| Value       | Description                                                                                                                                                              |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `stoe`      | Standard trust framework for identity verification                                                                                                                       |
| `stoe_etsi` | ETSI-compliant with stricter requirements. Requires `given_name` and `family_name` to be requested. Issuer check must be valid (only available for Norwegian documents). |

## Evidence Object

Each evidence object describes one piece of verification evidence.

> **Note:** Any requested evidence or claims that are not available in the ID check data will be omitted from the response. The response only contains data that was successfully retrieved.

### Document Evidence

```json
{
  "type": "document",
  "document_details": {
    "type": "passport",
    "document_number": "AB1234567",
    "date_of_issuance": "2020-01-15",
    "date_of_expiry": "2030-01-15",
    "issuer": {
      "country_code": "NOR",
      "name": "INNLANDET POLITIDISTRIKT"
    },
    "personal_number": "12345678901"
  },
  "check_details": [
    {
      "check_method": "vcrypt",
      "result": "success"
    },
    {
      "check_method": "data",
      "organization": "id.politiet.no",
      "time": "2024-01-15T10:30:00Z",
      "result": "valid"
    }
  ]
}
```

### Document Details Fields

| Field                 | Type   | Description                                                                                                                                                                           |
| --------------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`                | string | Document type                                                                                                                                                                         |
| `document_number`     | string | Document identification number                                                                                                                                                        |
| `date_of_issuance`    | string | Issue date (ISO 8601: `YYYY-MM-DD`)                                                                                                                                                   |
| `date_of_expiry`      | string | Expiry date (ISO 8601: `YYYY-MM-DD`)                                                                                                                                                  |
| `issuer`              | object | Issuing authority details                                                                                                                                                             |
| `issuer.country_code` | string | Issuing country (ISO 3166-1 alpha-3)                                                                                                                                                  |
| `issuer.name`         | string | Issuing authority name                                                                                                                                                                |
| `personal_number`     | string | For Norwegian documents, this is the fødselsnummer (NNIN). For non-Norwegian documents, this may contain a national identification number from the issuing country, or may be absent. |

### Document Type Values

| Value      | Description       |
| ---------- | ----------------- |
| `passport` | Passport document |
| `idcard`   | National ID card  |

### Document Check Details

The `check_details` array on document evidence provides OIDC4IA spec-aligned verification results. It is always included on document evidence.

```json
{
  "check_details": [
    {
      "check_method": "vcrypt",
      "result": "success"
    },
    {
      "check_method": "data",
      "organization": "id.politiet.no",
      "time": "2024-01-15T10:30:00Z",
      "result": "valid"
    }
  ]
}
```

| Field                          | Type   | Description                                                                                |
| ------------------------------ | ------ | ------------------------------------------------------------------------------------------ |
| `check_details`                | array  | Verification checks performed on the document                                              |
| `check_details[].check_method` | string | Check method: `vcrypt` (cryptographic verification) or `data` (registry/issuer data check) |
| `check_details[].result`       | string | Result of the check                                                                        |
| `check_details[].organization` | string | Authority that performed the check (data only)                                             |
| `check_details[].time`         | string | ISO 8601 timestamp of the check (data only)                                                |

#### vcrypt Check (Active Authentication)

Cryptographic verification of the document chip.

| Result           | Description                             |
| ---------------- | --------------------------------------- |
| `success`        | Document chip authentication successful |
| `failed`         | Document chip authentication failed     |
| `not_applicable` | Active authentication not performed     |

#### data Check (Issuer Registry Verification)

Verification against the issuing authority's registry. Only present for documents where an issuer check was performed (typically Norwegian documents).

| Result    | Description                                     |
| --------- | ----------------------------------------------- |
| `valid`   | Document verified as valid by issuing authority |
| `revoked` | Document has been revoked                       |

## Verified Identity Claims

The `claims` object contains the verified identity data.

```json
{
  "claims": {
    "name": "AASAMUND SPECIMEN OESTENBYEN",
    "given_name": "AASAMUND SPECIMEN",
    "family_name": "OESTENBYEN",
    "picture": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
    "birthdate": "1990-01-15",
    "gender": "male",
    "nationalities": ["NOR"]
  }
}
```

### Available Claims

| Claim           | Type      | Description                                                                    |
| --------------- | --------- | ------------------------------------------------------------------------------ |
| `name`          | string    | Full name                                                                      |
| `given_name`    | string    | First name(s)                                                                  |
| `family_name`   | string    | Last name(s)                                                                   |
| `picture`       | string    | Portrait photo from identity document (data URI: `data:image/jpeg;base64,...`) |
| `birthdate`     | string    | Date of birth (ISO 8601: `YYYY-MM-DD`)                                         |
| `gender`        | string    | Gender                                                                         |
| `nationalities` | string\[] | List of nationalities                                                          |

### Gender Values

| Value         | Description          |
| ------------- | -------------------- |
| `male`        | Male                 |
| `female`      | Female               |
| `unknown`     | Unknown gender       |
| `unspecified` | Gender not specified |

### Nationality Format

Nationalities are returned as ISO 3166-1 alpha-3 country codes:

| Code  | Country |
| ----- | ------- |
| `NOR` | Norway  |
| `SWE` | Sweden  |
| `DNK` | Denmark |
| `DEU` | Germany |
| etc.  |         |

## Conditional Claims

Claims are only included if:

1. **Requested in PAR**: The claim was included in the claims request (all claims must have `essential: true` — `essential: false` is rejected at PAR time)
2. **Available from source**: The ID Check service provided the data
3. **Consent given**: User consent was provided (if required)

If a requested claim is not available, it will be omitted from the response.

## Trust Framework Requirements

### `stoe` (Standard)

- All available claims are included
- Issuer check may be any value

### `stoe_etsi` (ETSI)

- Stricter validation requirements
- `given_name` and `family_name` **must** be requested as claims
- Issuer check **must** be `valid`
- If issuer check fails, an error is returned
- **Important:** Since issuer check is only available for Norwegian documents, the `stoe_etsi` trust framework can only be used with Norwegian passports and ID cards

## Token Validation

### Required Validations

1. **Decrypt the JWE** using your private key
2. **Verify the JWT signature** using DIP's public key from `/jwks`
3. **Validate standard claims**:

| Claim   | Validation                        |
| ------- | --------------------------------- |
| `iss`   | Must match DIP issuer URL         |
| `aud`   | Must match your `client_id`       |
| `exp`   | Must not be expired               |
| `iat`   | Must not be in the future         |
| `nonce` | Must match your PAR request nonce |

### Optional Validations

| Claim       | Validation                                                      |
| ----------- | --------------------------------------------------------------- |
| `acr`       | Should be `urn:bankid:idcheck`                                  |
| `amr`       | Should contain expected methods                                 |
| `auth_time` | Should be within acceptable timeframe                           |
| `jti`       | Track previously seen values to detect replay of the same token |

### Data Validation

The checks above cover token integrity. In addition, you should validate that the identity data itself is acceptable for your use case and compliance requirements.

DIP applies filtering during the verification process to reject documents early and provide useful feedback to end users, but these checks may not cover all of your specific requirements. Examples of additional validations to consider:

| Check           | Description                                                                   |
| --------------- | ----------------------------------------------------------------------------- |
| Issuer country  | Verify that the document's `issuer.country_code` is from a country you accept |
| Document type   | Verify that the `document_details.type` is acceptable for your use case       |
| Document expiry | Apply your own policy for how close to expiry you accept documents            |
| Check results   | Evaluate `check_details` results against your risk tolerance                  |
| Identity claims | Validate that the returned claims meet your business and compliance needs     |

As the Relying Party, you are responsible for your own compliance with applicable legislation, including verifying that the data you receive is sufficient for your purposes.

## Complete Example

### Request (PAR claims parameter)

```json
{
  "id_token": {
    "verified_claims": {
      "verification": {
        "trust_framework": { "value": "stoe" },
        "evidence": [
          {
            "type": { "value": "document" },
            "document_details": {
              "type": null,
              "document_number": null,
              "date_of_expiry": null,
              "issuer": null,
              "personal_number": null
            }
          }
        ]
      },
      "claims": {
        "given_name": { "essential": true },
        "family_name": { "essential": true },
        "picture": { "essential": true },
        "birthdate": { "essential": true }
      }
    }
  }
}
```

### Response (ID Token verified_claims)

```json
{
  "verified_claims": {
    "verification": {
      "trust_framework": "stoe",
      "evidence": [
        {
          "type": "document",
          "document_details": {
            "type": "passport",
            "document_number": "AB1234567",
            "date_of_expiry": "2030-01-15",
            "issuer": {
              "country_code": "NOR",
              "name": "INNLANDET POLITIDISTRIKT"
            },
            "personal_number": "12345678901"
          },
          "check_details": [
            {
              "check_method": "vcrypt",
              "result": "success"
            },
            {
              "check_method": "data",
              "organization": "id.politiet.no",
              "time": "2024-01-15T10:30:00Z",
              "result": "valid"
            }
          ]
        }
      ]
    },
    "claims": {
      "given_name": "AASAMUND SPECIMEN",
      "family_name": "OESTENBYEN",
      "picture": "data:image/jpeg;base64,/9j/4AAQSkZJRg...",
      "birthdate": "1990-01-15"
    }
  }
}
```

Note: Only requested fields are included in the response.

## Next Steps

- [PAR Request](https://docs.stoe.no/id-check/api/par.md) - How to request specific claims
- [Token Request](https://docs.stoe.no/id-check/api/token.md) - Token exchange endpoint
- [Authentication](https://docs.stoe.no/id-check/getting-started/authentication.md) - JWT requirements
