Use Cases
HomeIntegrityControlManagement CenterSolutions
  • Get Started
  • Integrity | Access
    • Auth. methods
      • LDAP (Username/Password)
      • LDAP (Username/Password) + OTP (SMTP)
      • LDAP (Username/Password) + OTP (SMS)
      • Swedish BankID
      • Microsoft Entra ID (SAMLSPBroker)
      • Certificate-Based Authentication
      • Foregin eID (SAMLSPBroker)
    • Auth. methods (SAML)
      • One-Time Password (OATH)
      • Inera IdP (SITHS) (SAMLSPBroker)
      • ID-porten (Norway) (SAML IdP with OIDC RP)
      • Multiple SAML IdP's configured
        • Multiple JSON files
    • Auth. methods (OIDC)
      • Static values (OIDC) - Test only
      • Swedish BankID (OIDC)
      • UID/PWD (OIDC)
    • Auth. methods (MISC)
      • Selector filtering
      • AuthZ control
      • External links and Cancel location
    • Add a Federation or SAML SP
  • Integrity | Portal
    • Portal
  • Integrity | Enrollment
    • Software token (OATH)
    • Best practice configuration
  • Integrity | Radius
    • UID/OATH token
    • UID/Password/OATH token
    • UID/Password/SMTP
  • Integrity | API
    • Swedish Siths eID
    • Oath Token
    • OIDC M2M Authentication & Token Service
  • Control | Applications
    • Password Reset
    • Password Reset for Entra ID
    • Password Reset for Google Workspace
  • OPERATION
    • Rolling upgrade - cluster
  • TROUBLESHOOTING
    • Wrong relaystate
  • Misc
    • Address configuration externally
    • ADFS
      • Protect Fortified ID apps
      • Install and configure Fortified ID ADFS adapter for Siths eID
      • Install and configure Fortified ID ADFS adapter for Oath
    • AWS
      • Protect AWS Cognito with eID MFA
      • Protect AWS IAM Identity Center with eID MFA
    • Customization
      • Overlay - WEB
      • Overlay - Portal
      • Overlay - Password Reset
      • Overlay - Enrollment
      • Logout page
    • Dependency-Track - protect with eID MFA and SSO
    • Digitala Nationella Prov (DNP) / Skolfederation
      • Active Directory Federation Services (ADFS) with BankID as step-up-method
      • Active Directory / LDAP with BankID as step-up-method
      • Entra ID (Azure AD) with BankID as step-up-method
      • Google with BankID as step-up-method
      • Generate eduPersonPrincipalName (eppn) and store in Google
      • Generate eduPersonPrincipalName (eppn) and store in Entra ID
      • Common configuration
    • Encrypt configuration secrets
    • Microsoft Entra
      • Protect Entra ID (Azure AD) with eID MFA
      • Entra External - Support for eID (SAML)
      • Entra External - Support for eID (OIDC)
    • Expressions
    • Google
      • Common configuration for Google Workspace - Directory API
      • Common configuration for Google Workspace - authentication for Fortified ID products
      • Delegated administration for Google Workspace - teacher updates student guardians
      • Delegated administration for Google Workspace - teacher updates student password
      • Protect Google Workspace with eID MFA
    • HTTPS
    • Protect sensitive data, such as social security numbers, through obfuscation
    • Reverse proxy
      • Install Apache Web Server on Windows
      • Add SSL certificate and enable https
      • Add a Fortified ID virtual host
      • mTLS in Apache HTTPD using a Self-Signed CA and Client Certificates
    • Set AuthnContextClassRef
    • Wiki.js - OpenID Connect (OIDC)
    • Add roles based on memberOf
Powered by GitBook
On this page
  • Table of Contents
  • Prerequisite
  • Endpoints
  • Pipe
  • Request/Response Flow
  • Testing & Examples
  1. Integrity | API

OIDC M2M Authentication & Token Service

This service exposes endpoints to support machine-to-machine OpenID Connect flows. The endpoints include the discovery document, JSON Web Key Set (JWKS), and the token issuance endpoint. The underlying processing is broken down into small, reusable “valves” that perform logging, assertions, JWT creation, and formatting of HTTP responses.

Note: The discovery and JWKS endpoints are public, while the token endpoint is protected via a dedicated authentication pipe.


Table of Contents

  1. Prerequisite

  2. Endpoints

    1. Discovery Endpoint

    2. JWKS Endpoint

    3. Token Endpoint

  3. Pipe

    1. Authentication Pipe (oidc_m2m_auth)

    2. Discovery Pipe (oidc_m2m_discovery)

    3. JWKS Pipe (oidc_m2m_jwks)

    4. Token Generation Pipe (oidc_m2m_token)

  4. Request/Response Flow

  5. Testing & Examples


Prerequisite

  • This use case assumes that you have good knowledge of the product in question.

  • Fortified ID Automate installed and configured with the default configuration


Endpoints

Add the following Endpoints to your Endpoint configuration.

Discovery Endpoint

  • URL: /oidc_m2m/.well-known/openid-configuration

  • Visibility: Public

  • Authentication: Not required

  • Request Pipe: oidc_m2m_discovery

  • Response Handler: DataProxy

Purpose: This endpoint returns the service’s OpenID Connect discovery document. The document provides clients with information such as the issuer URL, token endpoint, JWKS URI, supported scopes, grant types, and other protocol-related parameters. The discovery endpoint is exposed at the URL path oidc_m2m/.well-known/openid-configuration and is marked public. It requires no authentication (the auth.pipe is empty) and forwards requests to the oidc_m2m_discovery pipe. The response handler utilizes a DataProxy to directly relay data back to the requester.

Example: Discovery Endpoint Configuration

{
    "name": "oidc_m2m/.well-known/openid-configuration",
    "public": true,
    "auth": {
        "pipe": "",
        "headers": "*"
    },
    "request": {
        "pipe": "oidc_m2m_discovery",
        "headers": "*",
        "handler": "DataProxy"
    },
    "response": {
        "handler": "DataProxy"
    }
}

This configuration lets clients retrieve the OIDC configuration data (issuer, endpoints, supported scopes, etc.) that is formatted in a later valve pipe.

Discovery Document Example:

{
  "issuer": "https://192.168.126.128:8447/oidc_m2m",
  "token_endpoint": "https://192.168.126.128:8447/api/oidc_m2m",
  "jwks_uri": "https://192.168.126.128:8447/api/oidc_m2m/.well-known/openid-configuration/jwks",
  "scopes_supported": ["openid"],
  "grant_types_supported": ["client_credentials"],
  "id_token_signing_alg_values_supported": ["RS256"],
  "token_endpoint_auth_methods_supported": ["client_secret_post"],
  "claims_supported": ["iss", "aud", "your_claim"]
}

The response is generated via the HTTPFormatForAPI valve of the discovery pipe and is sent with appropriate HTTP headers for JSON content, no caching, and no-store semantics.


JWKS Endpoint

  • URL: /oidc_m2m/.well-known/openid-configuration/jwks

  • Visibility: Public

  • Authentication: Not required

  • Request Pipe: oidc_m2m_jwks

  • Response Handler: DataProxy

Purpose: This endpoint returns the JSON Web Key Set (JWKS) used by clients to validate the signature of tokens issued by the service. The JWKS endpoint is available at oidc_m2m/.well-known/openid-configuration/jwks and is marked public. It processes incoming requests via the oidc_m2m_jwks pipe and returns the JSON Web Key Set that includes public RSA key details for token verification.

Example: JWKS Endpoint Configuration

{
    "name": "oidc_m2m/.well-known/openid-configuration/jwks",
    "public": true,
    "auth": {
        "pipe": "",
        "headers": "*"
    },
    "request": {
        "pipe": "oidc_m2m_jwks",
        "headers": "*",
        "handler": "DataProxy"
    },
    "response": {
        "handler": "DataProxy"
    }
}

Clients and resource servers use these keys to verify the signature of the issued tokens.

JWKS Response Example:

{
  "keys": [
    {
      "kid": "rYPqdQrAj7_o3opqlILy3rIrSU3yBv0JKJ8_KMxHayk",
      "e": "AQAB",
      "x5c": [
        "MIIC6jCCAdKgAwIBAgIEYfp6GzANBgkqhkiG9w0BAQsFADA3MQswCQYDVQQGEwJzZTEUMBIGA1UECgwLZm9ydGlmaWVkaWQxEjAQBgNVBAMMCWRldmVsb3BlcjAeFw0yMjAyMDIxMjMzMzFaFw0yMzAyMDIxMjMzMzFaMDcx..."
      ],
      "alg": "RS256",
      "kty": "RSA",
      "x5t": "xrqyPnCrScUVx_r4dt7fcjbxPGo",
      "n": "q7dwcxC8EltwofGBaMQS_2e0ImkdEqjDI-1_TMjGD5p8nRVl8ttsOXv7X35rNjCzRO0BZFjeNAK3D64MeLQ8qkvwRV5RtHpcrFbI9WujJh8XYd_mz7xWiCThVEPzma91ySEYAHTg3W6YO2X3UfQINEV8a7fYB3g_bUGcBFNguI73D1EpaRA9DZCGXtUN5..."
      , "use": "sig"
    }
  ]
}

The HTTP response format is enforced with empty headers in this case. The valve processes the internal key definition and outputs the JWKS JSON.


Token Endpoint

  • URL: /oidc_m2m

  • Visibility: Private

  • Authentication: Uses authentication pipe oidc_m2m_auth

  • Request Pipe: oidc_m2m_token

  • Response Handler: DataProxy

Purpose: This endpoint handles token requests for machine-to-machine communication. It first validates the client credentials and then issues a JSON Web Token (JWT) as an access token. The token endpoint is the secured entry point for generating an access token. Unlike the discovery and JWKS endpoints, this one is not public. Instead, it employs an authentication pipe (oidc_m2m_auth) to validate client credentials before processing the token request via the oidc_m2m_token pipe.

Example: Token Endpoint Configuration

{
    "name": "oidc_m2m",
    "public": false,
    "auth": {
        "pipe": "oidc_m2m_auth",
        "headers": "*"
    },
    "request": {
        "pipe": "oidc_m2m_token",
        "headers": "*",
        "handler": "DataProxy"
    },
    "response": {
        "handler": "DataProxy"
    }
}

A valid request must successfully pass through the authentication check before a JWT is issued.

Token Response Example:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI...",
  "token_type": "Bearer",
  "expires_in": 300,
  "scope": "YourScope"
}

Access to this endpoint is restricted. A valid client must pass the correct client credentials; otherwise, the authentication pipe will reject the call.


Pipe

Each pipe is composed of several sequential valves. These valves perform operations such as logging, asserting values, creating internal items, formatting HTTP responses, and constructing JWTs. Add the following Pipes to your Pipe configuration.

Authentication Pipe (oidc_m2m_auth)

Purpose: Ensures the client is authorized to request a token. It dumps the request for logging, asserts that the client_id and client_secret match expected patterns (in this case, “app” and “secret” respectively), and creates an item to record the authentication context.

Example: Authentication Valve Configuration

{
    "id": "oidc_m2m_auth",
    "config": {
        "valves": [
            {
                "name": "DumpRequest",
                "config": {
                    "label": "**********   oidc_auth_dump  **********"
                }
            },
            {
                "name": "AssertValue",
                "config": {
                    "value": "${request.param_client_id}",
                    "regex": "app"
                }
            },
            {
                "name": "AssertValue",
                "config": {
                    "value": "${request.param_client_secret}",
                    "regex": "secret"
                }
            },
            {
                "name": "CreateItem",
                "config": {
                    "id": "oidc_m2m_auth"
                }
            }
        ]
    }
}

This pipe ensures that only valid clients (as determined by the custom regex patterns) can proceed to token issuance. Configured with settings that align with your environment

Valves:

  1. DumpRequest

    • Config: Logs the request using the label "********** oidc_auth_dump **********"

  2. AssertValue (client_id)

    • Config: Checks that the parameter ${request.param_client_id} matches the regex "app"

  3. AssertValue (client_secret)

    • Config: Checks that the parameter ${request.param_client_secret} matches the regex "secret"

  4. CreateItem

    • Config: Creates an item with the identifier "oidc_m2m_auth"

If any assertion fails, the pipe will halt and return an error to the client.


Discovery Pipe (oidc_m2m_discovery)

Purpose: Generates the OpenID Connect discovery document. After a valid discovery request, this valve creates an item in the pipe and formats the HTTP response with a full OIDC discovery document. The response includes critical URIs (issuer, token endpoint, and JWKS URI) as well as supported scopes and signature algorithms.

Example: Discovery Valve Configuration

{
    "id": "oidc_m2m_discovery",
    "config": {
        "valves": [
            {
                "name": "CreateItem",
                "config": {
                    "id": "oidc_m2m_discovery"
                }
            },
            {
                "name": "HTTPFormatForAPI",
                "enabled": true,
                "config": {
                    "body": {
                        "issuer": "https://192.168.126.128:8447/oidc_m2m",
                        "token_endpoint": "https://192.168.126.128:8447/api/oidc_m2m",
                        "jwks_uri": "https://192.168.126.128:8447/api/oidc_m2m/.well-known/openid-configuration/jwks",
                        "scopes_supported": [
                            "openid"
                        ],
                        "grant_types_supported": [
                            "client_credentials"
                        ],
                        "id_token_signing_alg_values_supported": [
                            "RS256"
                        ],
                        "token_endpoint_auth_methods_supported": [
                            "client_secret_post"
                        ],
                        "claims_supported": [
                            "iss",
                            "aud",
                            "your_claim"
                        ]
                    },
                    "headers": {
                        "Content-Type": "application/json",
                        "Cache-Control": "no-store",
                        "Pragma": "no-cache"
                    }
                }
            }
        ]
    }
}

This structured response helps clients automatically configure their OIDC interactions based on the advertised metadata. Configured with settings that align with your environment

Valves:

  1. CreateItem

    • Config: Creates an item with the identifier "oidc_m2m_discovery"

  2. HTTPFormatForAPI

    • Enabled: true

    • Config: Sets the response body with the following fields:

      • issuer: URL of the authentication service

      • token_endpoint: URL for token issuance

      • jwks_uri: URL for retrieving the JWKS

      • scopes_supported: e.g., ["openid"]

      • grant_types_supported: e.g., ["client_credentials"]

      • id_token_signing_alg_values_supported: e.g., ["RS256"]

      • token_endpoint_auth_methods_supported: e.g., ["client_secret_post"]

      • claims_supported: e.g., ["iss", "aud", "your_claim"]

    • Headers:

      • Content-Type: application/json

      • Cache-Control: no-store

      • Pragma: no-cache


JWKS Pipe (oidc_m2m_jwks)

Purpose: Creates and returns the JSON Web Key Set for token signature validation. This pipe prepares the key set that resource servers use when validating JWTs. Here, a public RSA key is provided along with metadata like key ID, algorithm, and exponent—all required for verifying token signatures.

Example: JWKS Valve Configuration

{
    "id": "oidc_m2m_jwks",
    "config": {
        "valves": [
            {
                "name": "CreateItem",
                "config": {
                    "id": "oidc_m2m_jwks"
                }
            },
            {
                "name": "HTTPFormatForAPI",
                "enabled": true,
                "config": {
                    "body": {
                        "keys": [
                            {
                                "kid": "rYPqdQrAj7_o3opqlILy3rIrSU3yBv0JKJ8_KMxHayk",
                                "e": "AQAB",
                                "x5c": [
                                    "MIIC6jCCAdKgAwIBAgIEYfp6GzANBgkqhkiG9w0BAQsFADA3MQswCQYDVQQGEwJzZTEUMBIGA1UECgwLZm9ydGlmaWVkaWQxEjAQBgNVBAMMCWRldmVsb3BlcjAeFw0yMjAyMDIxMjMzMzFaFw0yMzAyMDIxMjMzMzFaMDcxCzAJBgNVBAYTAnNlMRQwEgYDVQQKDAtmb3J0aWZpZWRpZDESMBAGA1UEAwwJZGV2ZWxvcGVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq7dwcxC8EltwofGBaMQS/2e0ImkdEqjDI+1/TMjGD5p8nRVl8ttsOXv7X35rNjCzRO0BZFjeNAK3D64MeLQ8qkvwRV5RtHpcrFbI9WujJh8XYd/mz7xWiCThVEPzma91ySEYAHTg3W6YO2X3UfQINEV8a7fYB3g/bUGcBFNguI73D1EpaRA9DZCGXtUN5bv/0vTtCAog1nntCcXIgQl/VU4IMCxeWmPbchVUgOOQZvQhFssYJS6YFQzBHzSw6IHZByfh/8ki7kFxMF579DoKd67gr23uAIrkpfAbHW/mmTZoqTcEff4eZ4UqQD9tmVNFTa9XTAVCxzVhQfW0KDAz+QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBt1l3k4ISeSzYc/wm6EH+io/fvX4N3ZMVX1Y1zk8M8+NgLvooK/C3Wa1YBaqeR8jpnSnDaCkzlGpA4pm9gUWoeCqqc4XZ8vobpuTsqqsDmOmIiX9FjeqemD6ra5qyFICiUyp48LTyX5x2ewxFNRjdgUPAVKwLYlnTXntSBiWovepz9E969RhxXE8ebjXvOEiu82U2unCHNcA7PMoMMbLkHg+m5DCvo5RuOlz/q2Bkr0nS4gkFBecrCQUDxihZWhs+gJRaaUg80wEuvF0/YYvKbB5mPe/QZ474bLP+P1SYn6M+DZQw/FqseTkgJbaVQTl0J238x848ZQPKjdeT0e73o"
                                ],
                                "alg": "RS256",
                                "kty": "RSA",
                                "x5t": "xrqyPnCrScUVx_r4dt7fcjbxPGo",
                                "n": "q7dwcxC8EltwofGBaMQS_2e0ImkdEqjDI-1_TMjGD5p8nRVl8ttsOXv7X35rNjCzRO0BZFjeNAK3D64MeLQ8qkvwRV5RtHpcrFbI9WujJh8XYd_mz7xWiCThVEPzma91ySEYAHTg3W6YO2X3UfQINEV8a7fYB3g_bUGcBFNguI73D1EpaRA9DZCGXtUN5bv_0vTtCAog1nntCcXIgQl_VU4IMCxeWmPbchVUgOOQZvQhFssYJS6YFQzBHzSw6IHZByfh_8ki7kFxMF579DoKd67gr23uAIrkpfAbHW_mmTZoqTcEff4eZ4UqQD9tmVNFTa9XTAVCxzVhQfW0KDAz-Q",
                                "use": "sig"
                            }
                        ]
                    },
                    "headers": {}
                }
            }
        ]
    }
}

This pipe returns the key set used by clients to confirm the validity of issued tokens. Configured with settings that align with your environment

Valves:

  1. CreateItem

    • Config: Creates an item with the identifier "oidc_m2m_jwks"

  2. HTTPFormatForAPI

    • Enabled: true

    • Config: Sets the response body with the keys array containing public key details such as:

      • kid, e, x5c, alg, kty, x5t, n, and use

    • Headers: Returns with an empty header object


Token Generation Pipe (oidc_m2m_token)

Purpose: Processes token requests, creates a JWT, and formats the token response. This pipe processes incoming token requests after successful authentication. It performs several steps:

  1. DumpRequest: Logs the inbound request for diagnostic purposes.

  2. CreateJwt: Generates a JSON Web Token with a short time-to-live (JWT TTL is 5 minutes in this example), and populates standard claims such as issuer, subject, audience, scope, and optionally echoes the client ID.

  3. HTTPFormatForAPI: Formats the HTTP response with a JSON object that includes the access token, token type, expiration (in seconds), and the scope.

  4. DumpState: Optionally logs the current processing state for debugging.

Example: Token Valve Configuration

{
    "id": "oidc_m2m_token",
    "config": {
        "valves": [
            {
                "name": "DumpRequest",
                "config": {
                    "label": "**********   oidc_dump  **********"
                }
            },
            {
                "name": "CreateJwt",
                "config": {
                    "dest": "access_token_jwt",
                    "jwt_ttl": 5,
                    "jwt_headers": {},
                    "jwt_claims": {
                        "iss": "https://192.168.126.128:8447/oidc_m2m",
                        "sub": "app",
                        "aud": "your_application",
                        "scope": "YourScope",
                        "client_id": "app"
                    },
                    "keystore": {
                        "path": "${globals.keystore_oidc_ref_path}",
                        "password": "${globals.keystore_oidc_ref_password}",
                        "type": "${globals.keystore_oidc_ref_type}"
                    },
                    "keystore_password": "${globals.keystore_oidc_key_alias}",
                    "keystore_alias": "${globals.keystore_oidc_key_password}"
                }
            },
            {
                "name": "HTTPFormatForAPI",
                "enabled": true,
                "config": {
                    "body": {
                        "access_token": "${item.access_token_jwt}",
                        "token_type": "Bearer",
                        "expires_in": 300,
                        "scope": "YourScope"
                    },
                    "headers": {
                        "Content-Type": "application/json",
                        "Cache-Control": "no-store",
                        "Pragma": "no-cache"
                    }
                }
            },
            {
                "name": "DumpState",
                "config": {
                    "label": "-----------  --------------"
                }
            }
        ]
    }
}

Here, note that the keystore and key information are injected via global variables, ensuring that sensitive cryptographic parameters remain centrally controlled. Configured with settings that align with your environment

Ensure that you add the following keys to your globals.json file, configured with settings that align with your environment:

  • keystore_oidc_ref_path

  • keystore_oidc_ref_password

  • keystore_oidc_ref_type

  • keystore_oidc_key_alias

  • keystore_oidc_key_password

Valves:

  1. DumpRequest

    • Config: Logs the incoming token request with the label "********** oidc_dump **********"

  2. CreateJwt

    • Config:

      • Destination: Stores the generated token in access_token_jwt

      • JWT TTL: 5 (interpreted as 5 minutes; the final response reflects 300 seconds)

      • JWT Claims:

        • iss: "https://192.168.126.128:8447/oidc_m2m" (issuer)

        • sub: "app" (subject – authenticated client)

        • aud: "your_application" (target API)

        • scope: "YourScope" (authorized scopes)

        • client_id: "app" (echoed client ID)

      • Keystore Configuration:

        • path, password, and type are drawn from global variables

        • keystore_password and keystore_alias are set accordingly

  3. HTTPFormatForAPI

    • Enabled: true

    • Config:

      • Body:

        • Returns the newly created token as access_token

        • Sets token_type to "Bearer"

        • expires_in: 300 seconds

        • scope: "YourScope"

      • Headers:

        • Content-Type: application/json

        • Cache-Control: no-store

        • Pragma: no-cache

  4. DumpState

    • Config: Logs the final processing state with the label "----------- --------------"


Request/Response Flow

  1. Discovery and JWKS Endpoints:

    • Clients can retrieve the OpenID Connect configuration and public keys without authentication. The system creates an item and immediately formats the response as JSON with the appropriate HTTP headers.

  2. Token Endpoint:

    • Clients must submit a request with parameters client_id and client_secret.

    • The authentication pipe (oidc_m2m_auth) validates these credentials.

    • If valid, the token generation pipe:

      • Logs the request

      • Creates a JWT with the configured claims

      • Formats and returns a JSON response containing the access token, its type, expiry period, and scope

    • Throughout, logging (via DumpRequest and DumpState) assists in debugging and auditing.


Testing & Examples

Discovery Endpoint: Using a simple HTTP GET:

curl https://192.168.126.128:8447/api/oidc_m2m/.well-known/openid-configuration

JWKS Endpoint: Access the public key set with:

curl https://192.168.126.128:8447/api/oidc_m2m/.well-known/openid-configuration/jwks

Token Endpoint: A protected call requires valid M2M credentials. For example, using client_secret_post:

curl -X POST https://192.168.126.128:8447/api/oidc_m2m \
  -d "client_id=app&client_secret=secret"

If successful, the response returns a JWT along with token meta details. Any deviation from expected credentials will cause the authentication valve to halt the request.


This documentation outlines the configuration and behavior of the OIDC M2M endpoints along with the pipe powering each request. By modularizing operations into distinct valves, the system maintains clarity, ease of debugging, and structured processing.

PreviousOath TokenNextPassword Reset

Last updated 2 days ago

If you’d like to explore more advanced configurations such as custom claims, alternative keystore settings, or additional valves for request transformation, see the **** .

Fortified ID Documentation