OpenID Connect Provider
=======================

Presentation
------------


.. note::

    OpenID Connect is a protocol based on REST, OAuth 2.0 and JOSE
    stacks. It is described here: http://openid.net/connect/.

LL::NG can act as an OpenID Connect Provider (OP). It will reply to
OpenID Connect requests to give user identity (through ID Token) and
information (through UserInfo endpoint).

As an OP, LL::NG supports many OpenID Connect features:

-  Authorization Code, Implicit and Hybrid flows
-  `Publication of JSON metadata and JWKS data (Discovery) <https://openid.net/specs/openid-connect-discovery-1_0.html>`__
-  ``prompt``, ``display``, ``ui_locales``, ``max_age`` parameters
-  :ref:`Mapping custom scope values to non-standard claims <oidcextraclaims>`
-  Authentication context Class References (ACR)
-  Authentication Method References (AMR) (Since ``2.21.0``)
-  Nonce
-  `Dynamic registration <https://openid.net/specs/openid-connect-registration-1_0.html>`__
-  Access Token Hash generation
-  ID Token signature (HS256/HS384/HS512 and RS256/RS384/RS512/PS256/PS384/PS512 or ES256/ES256K/ES384/ES512/EdDSA depending on the key type)
-  UserInfo endpoint, as JSON or as JWT
-  Request and Request URI
-  `Back Channel Logout <https://openid.net/specs/openid-connect-backchannel-1_0.html>`__
   (Since ``2.17.0``)
-  `Front Channel Logout <https://openid.net/specs/openid-connect-frontchannel-1_0.html>`__
-  `RP-Initiated Logout <https://openid.net/specs/openid-connect-rpinitiated-1_0.html>`__
-  PKCE (Since ``2.0.4``) - See :rfc:`7636`
-  Introspection endpoint (Since ``2.0.6``) - See :rfc:`7662`
-  JWT Introspection response (Since ``2.23.0``) - See :rfc:`9701`
-  Offline access (Since ``2.0.7``)
-  Refresh Tokens (Since ``2.0.7``)
-  Optional JWT Access Tokens (Since ``2.0.12``) - See :rfc:`9068`
-  `Form Post Response Mode <https://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html>`__ (Since ``2.0.16``)
-  Encrypted JWT (Since ``2.18.0``) - See :rfc:`7516`

Configuration
-------------

OpenID Connect Service
~~~~~~~~~~~~~~~~~~~~~~

See :doc:`OpenID Connect service<openidconnectservice>` configuration
chapter.


OpenID Connect Issuer Activation
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Go in ``General Parameters`` » ``Issuer modules`` » ``OpenID Connect``
and configure:

-  **Activation**: Set to ``On``
-  **Path**: Keep ``^/oauth2/`` unless you need to use another path
-  **Use rule**: Rule to allow user to use this module, set to ``1``
   to always allow


.. tip::

    For example, to allow only users with a strong authentication
    level:

    ::

       $authenticationLevel > 2



Configuration of LL::NG in Relying Party
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Each Relying Party has its own configuration way. LL::NG exposes
its OpenID Connect metadata to help clients configuration.

Metadata can be downloaded at the standard "Well Known" URL:
http://auth.example.com/.well-known/openid-configuration

OIDC metadata example:

.. code-block:: javascript

   {
      "end_session_endpoint" : "http://auth.example.com/oauth2/logout",
      "jwks_uri" : "http://auth.example.com/oauth2/jwks",
      "token_endpoint_auth_methods_supported" : [
         "client_secret_post",
         "client_secret_basic"
      ],
      "token_endpoint" : "http://auth.example.com/oauth2/token",
      "response_types_supported" : [
         "code",
         "id_token",
         "id_token token",
         "code id_token",
         "code token",
         "code id_token token"
      ],
      "userinfo_signing_alg_values_supported" : [
         "none",
         "HS256",
         "HS384",
         "HS512",
         "RS256",
         "RS384",
         "RS512",
         "PS256",
         "PS384",
         "PS512"
      ],
      "id_token_signing_alg_values_supported" : [
         "none",
         "HS256",
         "HS384",
         "HS512",
         "RS256",
         "RS384",
         "RS512",
         "PS256",
         "PS384",
         "PS512"
      ],
      "userinfo_endpoint" : "http://auth.example.com/oauth2/userinfo",
      "request_uri_parameter_supported" : "true",
      "acr_values_supported" : [
         "loa-4",
         "loa-1",
         "loa-3",
         "loa-5",
         "loa-2"
      ],
      "request_parameter_supported" : "true",
      "subject_types_supported" : [
         "public"
      ],
      "issuer" : "http://auth.example.com/",
      "grant_types_supported" : [
         "authorization_code",
         "implicit",
         "hybrid"
      ],
      "authorization_endpoint" : "http://auth.example.com/oauth2/authorize",
      "scopes_supported" : [
         "openid",
         "profile",
         "email",
         "address",
         "phone"
      ],
      "require_request_uri_registration" : "false",
      "registration_endpoint" : "http://auth.example.com/oauth2/register"
   }

Configuration of Relying Party in LL::NG
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Go in Manager and click on ``OpenID Connect Relying Parties``, then
click on ``Add OpenID Relying Party``. Set a technical name
(without space or special character), like “sample-rp”;

You can then set this RP configuration.

.. _oidcexportedattr:

Basic options
^^^^^^^^^^^^^

-  **Activation** The user can activate and deactivate a RP. By default, RPs are
   active upon creation.
-  **Public client** (since version ``2.0.4``): Set this RP as public
   client, so authentication is not needed on tokens endpoint. Set this for
   mobile apps or native Javascript apps.
-  **Client ID**: Client ID for this RP
-  **Client secret**: Client secret for this RP (can be used for
   symmetric signature)
-  **Allowed redirection addresses for login**: Space-separated list of redirect
   addresses allowed for this RP

Exported attributes (claims)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. versionchanged:: 2.0.16

   All exported attributes are sent if **Always send exported attributes** option is enabled in **OpenID Connect Service**. In previous versions, you had to declare them in **Options**/**Scope**/**Scope Values content** too.


For each OpenID Connect attribute you want to expose to applications, you can define:

* **Claim name**: Name of the attribute as it will appear in Userinfo responses
* **Variable name**: Name of the LemonLDAP::NG session variable containing the attribute value
* **Type**: Attribute data type. By default, it is a string. Choosing integer or boolean will make the attribute appear as the corresponding JSON type.
* **Array**: Select how multi-valued attributes are processed

  * **Automatic**: If the session key contains a single value, it will be released as a JSON number, string or boolean, depending on the previously specified type. If the session key contains multiple values, it will be released as an array of numbers, strings or booleans.
  * **Always**: Return an array even if the attribute only contains one value
  * **Never**: If the session key contains a single value, it will be released as a JSON number, string or boolean. If the session key contains multiple values, it will be released as a single string with a separator character.


.. attention::

    The specific ``sub`` attribute is not defined here, but in ``User attribute`` parameter (see below).

Options
^^^^^^^

-  **Advanced**

   -  **Bypass consent**: Enable if you never want to display the scope
      sharing consent screen (consent will be accepted by default).
      Bypassing the consent is **not** compliant with OpenID Connect
      standard.
   -  **Force claims to be returned in ID Token**: This options will
      make user attributes from the requested scope appear as ID Token claims
   -  **Use JWT format for Access Token** (since version ``2.0.12``): When
      using this option, Access Tokens will use the JWT format, which means they
      can be verified by external OAuth2.0 resource servers without using the
      Introspection or UserInfo endpoint.
   -  **Release claims in Access Token** (since version ``2.0.12``): If Access
      Tokens are in JWT format, this option lets you release the claims defined
      in the *Extra Claims* section inside the Access Token itself
   -  **Use refresh tokens** (since version ``2.0.7``): If this option
      is enabled, LL::NG will issue an *online* Refresh Token that can
      be used to obtain new access tokens as long as the user session
      is still valid. This token is tied to the SSO session: it becomes
      invalid when the user logs out or the session expires
   -  **User attribute**: Session field that will be used as main
      identifier (``sub``). Default value is ``whatToTrace``.
   -  **Additional audiences** (since version ``2.0.8``): You can
      specify a space-separated list of audiences that will be added to the
      ID Token audiences, and possibly the access token audiences if the
      access token format is JWT
   -  **Other RP allowed to exchange access_token** (since version ``2.20.0``):
      You can specify a space-separated list of Relying-Party allowed to ask
      for a token exchange. See :doc:`OpenID-Connect Token Exchange<oidctokenexchange>`
   -  **Don't insert typ header**: don't add the type header in JWT

-  **Scope**

   -  **Scope values content**: see :ref:`oidcextraclaims` below
   -  **Scope rules**: see :ref:`oidcscoperules` below

-  **Security**

   -  **Require PKCE** (since version ``2.0.4``): Controls PKCE validation
      at the Authorization and Token endpoints (see :rfc:`7636`). Available modes:

      - **Disabled**: PKCE is optional. If provided, it will be validated.
        For confidential clients, ``client_secret`` is required.
        For public clients, no authentication is required.
      - **Required**: PKCE is mandatory. Requests without ``code_challenge``
        are rejected at the Authorization endpoint. For confidential clients,
        both PKCE and ``client_secret`` are required.
      - **PKCE or Secret** (since version ``2.20.0``): For **public clients**,
        either PKCE or ``client_secret`` is required (at least one). This allows
        the same ``client_id`` to be used by mobile apps (with PKCE) and backend
        services (with secret). For confidential clients, this mode behaves
        like **Disabled** (secret always required, PKCE optional).
   -  **Invalidate refresh tokens after use** (since version ``2.20.0``): Use
      this option to prevent Refresh Tokens from being re-used. A new refresh
      token will be generated every time.
   -  **Allow offline access** (since version ``2.0.7``): After enabling
      this feature, an application may request the **offline_access**
      scope, and will obtain an *offline* Refresh Token that persists
      even after the user has logged off. Unlike online refresh tokens,
      offline tokens are not tied to the SSO session: they remain valid
      until their own expiration time. See
      https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess
      for details. These offline sessions can be administered through
      the Session Browser.

      These two options are independent. When both are enabled, the type
      of refresh token depends on the scope requested by the client:

      - Without ``offline_access`` scope: an *online* refresh token is
        issued (tied to the SSO session)
      - With ``offline_access`` scope: an *offline* refresh token is
        issued (survives logout)

      If only **Allow offline access** is enabled (without **Use refresh
      tokens**), applications will only receive a refresh token when
      they explicitly request the ``offline_access`` scope. Without
      that scope, no refresh token is issued.
   -  **Allow Native SSO for Mobile Apps** (since version ``2.21.0``): Allow
      relying party to request a **device_secret**. See
      https://openid.net/specs/openid-connect-native-sso-1_0.html for details.
   -  **Allow OAuth2.0 Password Grant** (since version ``2.0.8``): Allow the use of
      the :ref:`Resource Owner Password Credentials Grant <resource-owner-password-grant>` by this client.
      This feature only works if you have configured a form-based authentication module.
   -  **Allow OAuth2.0 Client Credentials Grant** (since version ``2.0.11``): Allow the use of the
      :ref:`Client Credentials Grant <client-credentials-grant>` by this client.
   -  **Allowed URLs for fetching Request Object**: (since version ``2.17.1``):
      which URLs may be called by the portal to fetch the request object (see
      `request_uri
      <https://openid.net/specs/openid-connect-core-1_0.html#RequestUriParameter>`__
      in OIDC specifications). These URLs may use wildcards (``https://app.example.com/*``).
   -  **Required authentication level**: Required authentication level to
      access this application. Since ``2.21.0`` this can be a Perl expression.
   -  **Access rule**: Lets you specify a :doc:`Perl rule<rules_examples>` to restrict access to this client
   -  **Token endpoint authentication method**: Fix method to use to connect to "token" endpoint
   -  **Require JWS for authorization requests**: Require a signed JWS for code authorization requests. If **Token endpoint authentication method** is set, it will require the same algorithm
   -  **Require "state" in authorization request**: Require 
   -  **Require "nonce" in authorization request**: Require 
   -  **userinfo endpoint authentication using header only**: 


-  **Algorithms**

   -  **Access Token signature algorithm** (since version ``2.0.12``): Select
      one of the available public key signature algorithms
   -  **Access Token Encryption key management algorithm**: If Relying-Party require access_token encryption, set here the key management algorithm
   -  **Access Token Encryption content encryption algorithm**: If Relying-Party require access_token encryption, set here the content encryption algorithm
   -  **ID Token signature algorithm**: Select one of the available public key
      (RSXXX) or HMAC (HSXXX) based signature algorithms
   -  **ID Token Encryption key management algorithm**: If Relying-Party require id_token encryption, set here the key management algorithm
   -  **ID Token Encryption content encryption algorithm**: If Relying-Party require id_token encryption, set here the content encryption algorithm
   -  **UserInfo response format** (since version ``2.0.12``): By default,
      UserInfo is returned as a simple JSON object. You can also choose to
      return it as a JWT, using one of the available signature algorithms. 
   -  **User_info Encryption key management algorithm**: If Relying-Party require user_info response encryption, set here the key management algorithm
   -  **User_info Encryption content encryption algorithm**: If Relying-Party require user_info response encryption, set here the content encryption algorithm
   -  **Introspection response format** (since version ``2.23.0``): By default,
      Introspection is returned as a simple JSON object (RFC 7662). You can also choose to
      return it as a JWT, using one of the available signature algorithms (RFC 9701).
   -  **Introspection Encryption key management algorithm**: If Relying-Party require introspection response encryption, set here the key management algorithm (RFC 9701)
   -  **Introspection Encryption content encryption algorithm**: If Relying-Party require introspection response encryption, set here the content encryption algorithm (RFC 9701)
   -  **Logout Encryption key management algorithm**: If Relying-Party require back-channel-logout token encryption, set here the key management algorithm
   -  **Logout Encryption content encryption algorithm**: If Relying-Party require back-channel-logout token encryption, set here the content encryption algorithm

-  **Keys**

   -  **JWKS URI**: When Relying-Party require encryption, set here the relying-party endpoint where keys are published
   -  **JWKS Data**: Alternative, fix here the relying-party JWKS document
   -  **Signing key name**: Since ``2.22.0``, lets you use a
      :doc:`different key <keys>` for signing tokens. If you specify multiple
      values separated by a comma, the first key will be used for signing, and the
      others will be published in metadata if you use the
      ``/oauth2/jwks?client_id=<clientid>`` endpoint

.. important::

    JWKS URI MUST be reachable by Portal to fetch JWKS document

-  **Timeouts**

   -  **Authorization Codes** *(default: one minute)*: Expiration time of
      Authorization Codes, when using the Authorization Code flow.
   -  **ID Tokens** *(default: one hour)*: Expiration time of ID Tokens.
   -  **Access Tokens** *(default: one hour)*: Expiration time
      of Access Tokens.
   -  **Offline sessions** *(default: one month)*: Lifetime of the
      refresh token obtained with the **offline_access** scope.
      This parameter only applies if offline sessions are enabled.
   -  **refresh_token activity timeout** *(default: none)*: Expiration time
      of inactives refresh tokens. if no value is set, activity isn't tracked.

.. important::

    When enabling **refresh_token activity timeout**, a refresh_token created
    with a version of LLNG previous to 2.22.0 and never used after update
    is considered as active *(because it has no activity field)*.
    Such totally inactive refresh_token will be purged normally at their
    normal end-of-life. Any use of a refresh_token updates the activity field.

-  **Logout**

   -  **Bypass confirm**: Bypass logout confirmation when logout is initiated
      by relying party
   -  **Session required**: Whether to send the Session ID *(sid)* in the logout
      request *(Front and Back Channel)*
   -  **Type**: Type of logout to perform
   -  **URL**: Specify the relying party's logout URL
   -  **Allowed redirection addresses for logout**: A space-separated list of
      URLs that this client can redirect the user to once the logout is done
      (through ``post_logout_redirect_uri``)

-  **Activation** The user can activate and deactivate a RP. By default, RPs are
   active upon creation.
-  **Comment**: set a comment

Macros
^^^^^^

You can define here macros that will be only evaluated for this service,
and not registered in the user's session.


Display
^^^^^^^

-  **Name**: Name of the RP application
-  **Logo**: Logo of the RP application

.. |beta| image:: /documentation/beta.png

.. _oidcextraclaims:

Scope values content
^^^^^^^^^^^^^^^^^^^^

When the **Always send exported attributes** option is disabled in **OpenID Connect Service**,
attributes can only be released if they are part of a scope.

By default, LL::NG will grant all requested scopes except if **Only allow declared scopes** option
is enabled in **OpenID Connect Service**. 

In this case, only `standard OpenID Connect claims
<http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims>`__ are
exposed to applications. If you want to add non-standard attributes, you have
to create a new scope in the *Scope values content* section and your
application must request that scope.

By default, the following scope-to-attributes are already mapped by LL::NG:

.. csv-table::
   :header: "Scope value", "Attribute list"
   :delim: ,
   :widths: auto

   profile, name family_name given_name middle_name nickname preferred_username profile picture website gender birthdate zoneinfo locale updated_at
   email, email email_verified
   address, street_address locality region postal_code country
   phone, phone_number phone_number_verified

If you want to expose custom attributes to OpenID Connect clients,
you have to declare them in a new scope in this section.

Add your additional scope as **Key**, and a space-separated list of
attributes as **Value**:

-  `employment_info` => `position company`

In this example, an OpenID Connect client (RP) requesting for the ``employment_info`` scope will
be able to read the ``company`` and ``position`` attributes from the UserInfo endpoint.

.. important::

    Any attribute defined in this section must be mapped to a
    LL::NG session variable in **Exported Attributes** section

.. important::

    Your custom attributes will only be visible if the application requests the
    corresponding scope value, or if you use a Scope Rule to always enable that scope.


.. _oidcscoperules:

Scope rules
^^^^^^^^^^^

.. versionadded:: 2.0.12

|beta| This feature may change in a future version in a way that breaks
compatibility with existing configuration.

By default, LL::NG grants all scopes requested by the application, as
long as the user consents to them.

This configuration screen allows you to change that behavior by attaching
:ref:`a rule<rules>` to a particular scope.

* If the rule evaluates to true, the scope is added to the current request,
  even if it was not requested by the application
* If the rule evaluates to false, the scope is removed from the current request
* Scopes which are not declared in the "Scope rules" list are left untouched

When writing scope rules, you can use the special ``$requested`` variable. This
variables evaluates to `true` within a scope rule when the corresponding scope
has been requested by the application. You can use this variable in a dynamic
rule when you only want to add a scope when the application requested it.

Examples:

* ``read``: ``inGroup('readers')``

  * the ``read`` scope will be granted if the user is a member of the ``readers`` group even if the application did not request it.

* ``write``: ``$requested and inGroup('writers')``

  * the ``write`` scope will be granted if the user is a member of the ``writers`` group, but only if the application requested it.

Access rule extra variables
^^^^^^^^^^^^^^^^^^^^^^^^^^^

When writing your access rules, you can additionally use the following variables:

* ``$_oidc_grant_type`` (since version ``2.0.14``): the grant type being used to
  access this service. Possible values: ``authorizationcode``,
  ``implicit``, ``hybrid``, ``clientcredentials``, ``password``

The following attributes are made available in the created session:

* The ``_whatToTrace`` attribute (main session identifier), is set to the
  relying party's Client ID
* The ``_scope`` attribute is set to the requested scopes
* The ``_clientId`` attribute is set to the Client ID that obtained the access
  token.
* The ``_clientConfKey`` attribute is set to the LemonLDAP::NG configuration
  key for the client that obtained the access token.

The **Access Rule**, if defined, will have access to those variables, as well as
the `@ENV` array. You can use it to restrict the use of this grant to
pre-determined scopes, a particular IP address, etc.

These session attributes will be released on the UserInfo endpoint if they are
mapped to **Exported Attributes** and **Extra Claims**.

.. _resource-owner-password-grant:

Resource Owner Password Credentials Grant
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The Resource Owner Password Credentials Grant allows you to exchange a user's login and password for an access token. This must be considered a legacy form of authentication, since the Authorization Code web-based flow is prefered for all applications that support it. It can however be useful in some scenarios involving technical accounts that cannot implement a web-based authentication flow.

.. versionchanged:: 2.0.12

   When using the :doc:`Choice <authchoice>` authentication module, the *Choice used for password authentication* setting can be used for selecting which authentication choice is used by the Resource Owner Password Credentials Grant. Naturally, the selected choice must be a password-based authentication method (LDAP, DBI, REST, etc.).

.. seealso::

   Specification for the Resource Owner Password Credentials Grant: :rfc:`6749#section-4.3`

.. _client-credentials-grant:

Client Credentials Grant
^^^^^^^^^^^^^^^^^^^^^^^^

The Client Credentials Grant allows you to obtain an Access Token using only a Relying Party's Client ID and Client Secret.

.. seealso::

   Specification for the Client Credentials Grant: :rfc:`6749#section-4.4`
