# Single Sign-On with Microsoft Active Directory FS


> Enable OpenID Connect-based single sign-on (SSO) for applications proxied by NGINX Plus, using Microsoft AD FS as the identity provider (IdP).


This guide explains how to enable single sign-on (SSO) for applications being proxied by F5 NGINX Plus. The solution uses OpenID Connect as the authentication mechanism, with [Microsoft Active Directory Federation Services](https://docs.microsoft.com/en-us/windows-server/identity/active-directory-federation-services) (AD FS) as the Identity Provider (IdP) and NGINX Plus as the Relying Party (RP), or OIDC client application that verifies user identity.

**Note:**  This guide applies to [NGINX Plus Release 36](nginx/releases.md#r36) and later. In earlier versions, NGINX Plus relied on an [njs-based solution](#legacy-njs-guide), which required NGINX JavaScript files, key-value stores, and advanced OpenID Connect logic. In the latest NGINX Plus version, the new [OpenID Connect module](https://nginx.org/en/docs/http/ngx_http_oidc_module.html) simplifies this process to just a few directives.

## Prerequisites

- A Microsoft AD FS instance, either on-premises or in [Azure](https://learn.microsoft.com/en-us/windows-server/identity/ad-fs/deployment/how-to-connect-fed-azure-adfs), with administrator privileges.

- An NGINX Plus [subscription](https://www.f5.com/products/nginx/nginx-plus) and NGINX Plus [Release 36](nginx/releases.md#r36) or later. For installation instructions, see [Installing NGINX Plus](https://docs.nginx.com/nginx/admin-guide/installing-nginx/installing-nginx-plus/).

- A domain name pointing to your NGINX Plus instance, for example, `demo.example.com`.

## Configure the AD FS Server {#adfs-setup}

[Microsoft Active Directory Federation Services](https://docs.microsoft.com/en-us/windows-server/identity/active-directory-federation-services) (AD FS) serves as the Identity Provider.

### Create an AD FS Application

1. In AD FS, open the Server Manager.

2. In Server Manager, select **Tools**, and then select **AD FS Management**.

3. In **AD FS Management**, right-click on **Application Groups** and select **Add Application Group**.

4. On the Application Group Wizard **Welcome** screen:

   - Enter the Name of your application, for example, `NGINX Demo App`.

   - Under **Standalone applications**, select **Server application**.

   <span id="adfs-setup-id"></span>
5. On the Application Group Wizard **Server application** screen:

    - Copy the **Client Identifier** value generated by AD FS. The client identifier is your AD FS Application ID, you will need it later when configuring NGINX Plus.

    - In **Redirect URI**, enter the Redirect URI for your NGINX Plus instance, for example, `https://demo.example.com/oidc_callback`, and then click **Add**.

   <span id="adfs-setup-secret"></span>
6. On the Application Group Wizard **Configure Application Credentials** screen:

   - Select **Generate a shared secret**.

   - Copy and save the generated **Client Secret**, you will need it later when configuring NGINX Plus. You will not be able to view the secret after the application group is created.

   - Select **Next** to complete the steps for adding the application group.

### Configure Logout URLs

After creating the application group, you need to configure the logout URLs to support RP-initiated logout:

1. In **AD FS Management**, navigate to **Application Groups** and select your application group.

2. Right-click on the application group and select **Properties**.

3. In the **Properties** dialog, add the post logout redirect URI to the application configuration:

   - Add the post logout URL, for example: `https://demo.example.com/post_logout/`.

4. To enable OpenID Connect front-channel logout (single sign-out when the user signs out of another application):

    - Use PowerShell to configure a **LogoutUri** for the AD FS client (there is no GUI option for this). For example, run:
      
      ```powershell
      Set-AdfsClient -TargetClientId <client-id> -LogoutUri https://demo.example.com/front_logout/
      ```
      Replace `<client-id>` with the Client Identifier from [Step 5](#adfs-setup-id) above (the AD FS Application ID) and substitute the domain name of your NGINX Plus instance for `demo.example.com`.
      
      This registers a front-channel logout URL (`LogoutUri`) for the client in AD FS. When a user signs out of this or any other application in AD FS, the AD FS server sends a GET request to this URL (typically via a hidden iframe) with the user's session ID (`sid`) as a query parameter, instructing NGINX Plus to clear the user's session. According to the OpenID Connect front-channel logout specification, the identity provider is supposed to send both an issuer (`iss`) and a session ID; AD FS provides only the `sid` parameter, but the NGINX Plus OIDC module supports both the fully compliant `iss+sid` and the `sid`-only variants and will clear the session in either case.

### Get the OpenID Connect Discovery URL

Check the OpenID Connect endpoint URL. By default, AD FS publishes the `.well-known/openid-configuration` document at the following address:

`https://adfs-server-address/adfs/.well-known/openid-configuration`.

1. Run the following `curl` command in a terminal:

   ```shell
   curl https://adfs-server-address/adfs/.well-known/openid-configuration | jq .
   ```
   
   Where:

   - the `adfs-server-address` is your AD FS server address

   - the `/adfs/.well-known/openid-configuration` is the default address for AD FS for document location

   - the `jq` command (optional) is used to format the JSON output for easier reading and requires the [jq](https://jqlang.github.io/jq/) JSON processor to be installed.

   The configuration metadata is returned in the JSON format:

   ```json
   {
       ...
       "issuer": "https://adfs-server-address/adfs",
       "authorization_endpoint": "https://adfs-server-address/adfs/oauth2/authorize/",
       "token_endpoint": "https://adfs-server-address/adfs/oauth2/token/",
       "jwks_uri": "https://adfs-server-address/adfs/discovery/keys",
       "userinfo_endpoint": "https://adfs-server-address/adfs/userinfo",
       "end_session_endpoint": "https://adfs-server-address/adfs/oauth2/logout",
       "frontchannel_logout_supported": true,
       "frontchannel_logout_session_supported": true
       ...
   }
   ```

   <span id="adfs-setup-issuer"></span>
2. Copy the **issuer** value, you will need it later when configuring NGINX Plus. Typically, the OpenID Connect Issuer for AD FS is:

   `https://adfs-server-address/adfs`.

**Note:**  You will need the values of **Client ID**, **Client Secret**, and **Issuer** in the next steps. 

## Set up NGINX Plus {#nginx-plus-setup}

With AD FS configured, you can enable OIDC on NGINX Plus. NGINX Plus serves as the Rely Party (RP) application — a client service that verifies user identity.

1.  Ensure that you are using the latest version of NGINX Plus by running the `nginx -v` command in a terminal:

    ```shell
    nginx -v
    ```

    The output should match NGINX Plus Release 36 or later:

    ```text
    nginx version: nginx/1.29.3 (nginx-plus-r36)
    ```

2.  Ensure that you have the values of the **Client ID**, **Client Secret**, and **Issuer** obtained during [AD FS Configuration](#adfs-setup).

3.  In your preferred text editor, open the NGINX configuration file (`/etc/nginx/nginx.conf` for Linux or `/usr/local/etc/nginx/nginx.conf` for FreeBSD).

4.  In the [`http {}`](https://nginx.org/en/docs/http/ngx_http_core_module.html#http) context, make sure your public DNS resolver is specified with the [`resolver`](https://nginx.org/en/docs/http/ngx_http_core_module.html#resolver) directive. By default, NGINX Plus re‑resolves DNS records at the frequency specified by time‑to‑live (TTL) in the record, but you can override the TTL value with the `valid` parameter:

    ```nginx
    http {
        resolver 10.0.0.1 ipv4=on valid=300s;

        # ...
    }
    ```

5.  In the [`http {}`](https://nginx.org/en/docs/http/ngx_http_core_module.html#http) context, define the AD FS OIDC provider named `adfs` by specifying the [`oidc_provider {}`](https://nginx.org/en/docs/http/ngx_http_oidc_module.html#oidc_provider) context:

    ```nginx
    http {
        resolver 10.0.0.1 ipv4=on valid=300s;

        oidc_provider adfs {

            # ...

        }
        # ...
    }
    ```

6.  In the [`oidc_provider {}`](https://nginx.org/en/docs/http/ngx_http_oidc_module.html#oidc_provider) context, specify:

    - Your actual AD FS **Client ID** from [Step 5](#adfs-setup-id) of AD FS Configuration with the [`client_id`](https://nginx.org/en/docs/http/ngx_http_oidc_module.html#client_id) directive

    - Your **Client Secret** from [Step 6](#adfs-setup-secret) of AD FS Configuration with the [`client_secret`](https://nginx.org/en/docs/http/ngx_http_oidc_module.html#client_secret) directive

    - The **Issuer** URL from [Step 2](#adfs-setup-issuer) of AD FS Configuration with the [`issuer`](https://nginx.org/en/docs/http/ngx_http_oidc_module.html#client_secret) directive

      The `issuer` is typically your AD FS OIDC URL. By default, NGINX forms the provider metadata endpoint by appending `.well-known/openid-configuration` to the issuer. For AD FS, this often resolves to `https://adfs-server-address/adfs/.well-known/openid-configuration`. If your AD FS issuer differs from `https://adfs-server-address/adfs` (for example, a custom path), you can explicitly specify the metadata document with the [`config_url`](https://nginx.org/en/docs/http/ngx_http_oidc_module.html#config_url) directive.

    - The **logout_uri** is URI that a user visits to start an RP‑initiated logout flow.

    - The **frontchannel_logout_uri** directive defines the URI that receives OpenID Connect front-channel logout requests from AD FS. This URI must be an HTTPS path and must match the LogoutUri configured for the client in AD FS. When AD FS triggers a front-channel logout (for example, when a user signs out of another application), it sends a GET request to this URI (typically via a hidden iframe) with the session ID (sid) as a query parameter. The OIDC module clears the corresponding user session on NGINX Plus.

    - The **post_logout_uri** is absolute HTTPS URL where AD FS should redirect the user after a successful logout. This value **must also be configured** in the AD FS application properties.

    - If the **logout_token_hint** directive set to `on`, NGINX Plus sends the user's ID token as a *hint* to AD FS.
      This directive is **optional**, however, if it is omitted the AD FS may display an extra confirmation page asking the user to approve the logout request.

    - If the **userinfo** directive is set to `on`, NGINX Plus will fetch `/userinfo` from the AD FS and append the claims from userinfo to the `$oidc_claims_` variables.

    - PKCE (Proof Key for Code Exchange) is automatically enabled when the provider's OpenID Connect discovery document advertises the S256 code challenge method in the code_challenge_methods_supported field. You can override this behavior with the pkce directive: set `pkce off;` to disable PKCE even when S256 is advertised, or `pkce on;` to force PKCE even if the IdP's metadata does not list S256.

    - **Note:**  All interaction with the IdP is secured exclusively over SSL/TLS, so NGINX must trust the certificate presented by the IdP. By default, this trust is validated against your system's CA bundle (the default CA store for your Linux or FreeBSD distribution). If the IdP's certificate is not included in the system CA bundle, you can explicitly specify a trusted certificate or chain with the [`ssl_trusted_certificate`](https://nginx.org/en/docs/http/ngx_http_oidc_module.html#ssl_trusted_certificate) directive so that NGINX can validate and trust the IdP's certificate. 

    ```nginx
    http {
        resolver 10.0.0.1 ipv4=on valid=300s;

        oidc_provider adfs {
            issuer                  https://adfs.example.com/adfs;
            client_id               <client_id>;
            client_secret           <client_secret>;
            logout_uri              /logout;
            post_logout_uri         https://demo.example.com/post_logout/;
            frontchannel_logout_uri /front_logout;
            logout_token_hint       on;
            userinfo                on;

            # Optional: PKCE configuration. By default, PKCE is automatically
            # enabled when the IdP advertises the S256 code challenge method.
            # pkce                  on;
        }

        # ...
    }
    ```

7.  Make sure you have configured a [server](https://nginx.org/en/docs/http/ngx_http_core_module.html#server) that corresponds to `demo.example.com`, and there is a [location](https://nginx.org/en/docs/http/ngx_http_core_module.html#location) that [points](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass) to your application (see [Step 10](#oidc_app)) at `http://127.0.0.1:8080` that is going to be OIDC-protected:

    ```nginx
    http {

        # ...

        server {
            listen      443 ssl;
            server_name demo.example.com;

            ssl_certificate     /etc/ssl/certs/fullchain.pem;
            ssl_certificate_key /etc/ssl/private/key.pem;

            location / {

                # ...

                proxy_pass http://127.0.0.1:8080;
            }
        }
        # ...
    }
    ```

8.  Protect this [location](https://nginx.org/en/docs/http/ngx_http_core_module.html#location) with AD FS OIDC by specifying the [`auth_oidc`](https://nginx.org/en/docs/http/ngx_http_oidc_module.html#auth_oidc) directive that will point to the `adfs` configuration specified in the [`oidc_provider {}`](https://nginx.org/en/docs/http/ngx_http_oidc_module.html#oidc_provider) context in [Step 5](#adfs-setup-oidc-provider):

    ```nginx
    # ...
    location / {

         auth_oidc adfs;

         # ...

         proxy_pass http://127.0.0.1:8080;

    }
    # ...
    ```

9.  Pass the OIDC claims as headers to the application ([Step 10](#oidc_app)) with the [`proxy_set_header`](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_set_header) directive. These claims are extracted from the ID token returned by AD FS:

    - [`$oidc_claim_sub`](https://nginx.org/en/docs/http/ngx_http_oidc_module.html#var_oidc_claim_) - a unique `Subject` identifier assigned for each user by AD FS

    - [`$oidc_claim_email`](https://nginx.org/en/docs/http/ngx_http_oidc_module.html#var_oidc_claim_) the e-mail address of the user

    - [`$oidc_claim_name`](https://nginx.org/en/docs/http/ngx_http_oidc_module.html#var_oidc_claim_) - the full name of the user

    - any other OIDC claim using the [`$oidc_claim_ `](https://nginx.org/en/docs/http/ngx_http_oidc_module.html#var_oidc_claim_) variable

    ```nginx
    # ...
    location / {

         auth_oidc adfs;

         proxy_set_header sub   $oidc_claim_sub;
         proxy_set_header email $oidc_claim_email;
         proxy_set_header name  $oidc_claim_name;

         proxy_pass http://127.0.0.1:8080;
    }
    # ...
    ```

    <span id="oidc_app"></span>
10. Provide endpoint for completing logout:

    ```nginx
    # ...
    location /post_logout/ {
         return 200 "You have been logged out.\n";
         default_type text/plain;
    }
    # ...
    ```

11. Create a simple test application referenced by the `proxy_pass` directive which returns the authenticated user's full name and email upon successful authentication:

    ```nginx
    # ...
    server {
        listen 8080;

        location / {
            return 200 "Hello, $http_name!\nEmail: $http_email\nAD FS sub: $http_sub\n";
            default_type text/plain;
        }
    }
    ```
    
12. Save the NGINX configuration file and reload the configuration:

    ```nginx
    nginx -s reload
    ```

### Complete Example

This configuration example summarizes the steps outlined above. It includes only essential settings such as specifying the DNS resolver, defining the OIDC provider, configuring SSL, and proxying requests to an internal server.

```nginx
http {
    # Use a public DNS resolver for Issuer discovery, etc.
    resolver 10.0.0.1 ipv4=on valid=300s;

    oidc_provider adfs {

        # The 'issuer' is typically your AD FS OIDC URL
        # e.g. https://adfs.example.com/adfs
        issuer https://adfs.example.com/adfs;

        # Replace with your actual AD FS Client ID and Secret
        client_id     <client_id>;
        client_secret <client_secret>;

        # RP‑initiated logout
        logout_uri /logout;
        post_logout_uri https://demo.example.com/post_logout/;
        logout_token_hint on;

        # Front-channel logout
        frontchannel_logout_uri /front_logout;

        # Fetch userinfo claims
        userinfo on;

        # Optional: PKCE configuration (enabled automatically when supported by the IdP)
        # pkce on;
    }

    server {
        listen      443 ssl;
        server_name demo.example.com;

        ssl_certificate     /etc/ssl/certs/fullchain.pem;
        ssl_certificate_key /etc/ssl/private/key.pem;

        location / {
            # Protect this location with AD FS OIDC
            auth_oidc adfs;

            # Forward OIDC claims as headers if desired
            proxy_set_header sub   $oidc_claim_sub;
            proxy_set_header email $oidc_claim_email;
            proxy_set_header name  $oidc_claim_name;

            proxy_pass http://127.0.0.1:8080;
        }

        location /post_logout/ {
            return 200 "You have been logged out.\n";
            default_type text/plain;
        }
    }

    server {
        # Simple test upstream server
        listen 8080;

        location / {
            return 200 "Hello, $http_name!\nEmail: $http_email\nAD FS sub: $http_sub\n";
            default_type text/plain;
        }
    }
}
```

### Testing

1. Open `https://demo.example.com/` in a browser. You will be automatically redirected to the AD FS sign-in page.

2. Enter valid AD FS credentials of a user who has access the application. Upon successful sign-in, AD FS redirects you back to NGINX Plus, and you will see the proxied application content (for example, "Hello, Jane Doe!").

3. Navigate to `https://demo.example.com/logout`. NGINX Plus initiates an RP‑initiated logout; AD FS ends the session and redirects back to `https://demo.example.com/post_logout/`.

4. Refresh `https://demo.example.com/` again. You should be redirected to AD FS for a fresh sign‑in, proving the session has been terminated.

## Legacy njs-based AD FS Solution {#legacy-njs-guide}

If you are running NGINX Plus R33 and earlier or if you still need the njs-based solution, refer to the [Legacy njs-based Microsoft AD FS Guide](nginx/deployment-guides/single-sign-on/oidc-njs/active-directory-federation-services.md) for details. The solution uses the [`nginx-openid-connect`](https://github.com/nginxinc/nginx-openid-connect) GitHub repository and NGINX JavaScript files.

## See Also

- [NGINX Plus Native OIDC Module Reference documentation](https://nginx.org/en/docs/http/ngx_http_oidc_module.html)

- [Release Notes for NGINX Plus R36](nginx/releases.md#r36)

## Revision History

- Version 3 (November 2025) – Updated for NGINX Plus R36; added front-channel logout support (`frontchannel_logout_uri`), PKCE configuration (`pkce` directive), and the `client_secret_post` token endpoint authentication method.

- Version 2 (August 2025) – Updated for NGINX Plus R35; added RP‑initiated logout (`logout_uri`, `post_logout_uri`, `logout_token_hint`) and `userinfo` support.

- Version 1 (March 2025) – Initial version (NGINX Plus Release 34).

