NGINX.COM
Web Server Load Balancing with NGINX Plus

Using JWT support to provide SSO for existing applications

[Editor – This post describes how to use NGINX Plus with OpenID Connect providers that support the Implicit Flow for authentication. The information is technically correct, but some actions (such as using cron to fetch public keys) are no longer necessary because of updates to our reference implementation. For the current implementation, see our GitHub repo.

In NGINX Plus R15 and later, you can also use NGINX Plus as the Relying Party in the OpenID Connect Authorization Code Flow.]

OAuth 2.0 has done much to transform the flexibility and user experience of authenticating to websites and applications. But despite the name, the OAuth 2.0 specification says very little about verifying end‑user identity and nothing about single sign‑on (SSO). That’s where OpenID Connect comes in – it is essentially the missing piece that carries identity information in OAuth 2.0 access tokens.

OpenID Connect identity tokens comply with the JSON Web Token (JWT) specification. JWT (pronounced “jot”) tokens are compact, easy to pass around, and provide a common core schema for describing identity information. The great thing about JWTs is that they can be applied to almost any identity use case, from authenticating API clients to providing SSO for enterprise applications. In fact, many organizations that use Google Apps can utilize Google as the identity provider to provide SSO to their enterprise applications. That said, the use of OpenID Connect and JWTs does not prevent them being used to authenticate to, or provide SSO for, existing web applications.

NGINX Plus R10 and later includes native JWT support, enabling NGINX Plus to validate tokens and decorate upstream requests with the identity of the authenticated user in a way that the application can easily consume. In this blog post we demonstrate how to use the native JWT support in NGINX Plus to enable SSO for existing applications without any changes required to the applications themselves. We’re using Google as the identity provider and a simple website to represent the application. The end‑to‑end flow looks like this:

Diagram depicting the processing flow for single sign-on (SSO) of clients with Google accounts; NGINX Plus validates user identity using OAuth 2.0 and OpenID Connect tokens, which comply with the JSON Web Token (JWT) standard
NGINX Plus validates user identity using OAuth 2.0 and OpenID Connect for Google‑based SSO

Enabling OpenID Connect for Your Web Application

Our example has two components: the NGINX Plus configuration and the HTML login page.

NGINX Plus Configuration

The NGINX Plus configuration for validating JWTs is very simple.

server {
    listen 80;
    root /var/www/public_html;

    location /private/ {
        auth_jwt "Google account" token=$cookie_auth_token;
        auth_jwt_key_file /etc/nginx/google_certs.jwk;
    }
}

The location block specifies that any requests to URLs beginning with /private/ must be authenticated. The auth_jwt directive defines the authentication realm that will be returned (along with a 401) if authentication is unsuccessful, and where in the request NGINX Plus can find the JWT. In this case it expects to find the token in a cookie named auth_token. By default, NGINX Plus expects clients to present the JWT as a Bearer Token, using the Authorization header as is common with AJAX applications and API clients, but it can also obtain the JWT from other HTTP headers, query string arguments, or a cookie as in this example.

The auth_jwt_key_file directive tells NGINX how to validate the signature element of the JWT. Signature validation ensures that the JWT was issued by Google and has not been modified since. Google publishes its public keys and refreshes them regularly. To maintain an up‑to‑date set of keys, use cron(8) to fetch them hourly, as in this sample crontab entry.

0 * * * * wget https://www.googleapis.com/oauth2/v3/certs -O /etc/nginx/google_certs.jwk

HTML-Based Login Page

To keep this example simple and straightforward, we aren’t building an entire application. Instead we’re using the following basic HTML to create a login page. The HTML file is called /var/www/public_html/index.html (this matches the root path we defined in the NGINX Plus configuration).

<html>
<head>
    <meta http-equiv="cache-control" content="no-cache" />
    <meta http-equiv="expires" content="0" />
    <title>NGINX OpenID Connect demo</title>
    <script src="https://apis.google.com/js/platform.js" async defer></script>
    <meta name="google-signin-scope" content="profile email">
    <meta name="google-signin-client_id" 
          content="client-ID.apps.googleusercontent.com">
    <script src="/js.cookie.js"></script>
</head>
<body>
    <h2>NGINX OpenID Connect demo</h2>
    <hr/>
    <h3>Login with a Google account then visit the <a href="/private/">private area</a>.</h3>
    <table><tr><td>
    <div class="g-signin2" data-onsuccess="onSignIn" data-theme="dark"></div></td>
    <script>
      function onSignIn(googleUser) {
        var profile = googleUser.getBasicProfile();
        Cookies.set('auth_token', googleUser.getAuthResponse().id_token);
        document.getElementById('google_signout').innerHTML = '<a href="#" onclick="signOut();"><img src="' + profile.getImageUrl() + '" width=32 height=32>Sign out</a>';
      };
      function signOut() {
        var auth2 = gapi.auth2.getAuthInstance();
        auth2.signOut().then(function () {
          Cookies.remove('auth_token');
          document.getElementById('google_signout').innerHTML = '';
        });
      }
    </script>
    <td><div id="google_signout"></div></td>
    </tr></table>
    <hr/>
</body>
</html>

We’ve highlighted two key dependencies in the <head> block.

  • <meta name="google‑signin‑client_id"> tag – We are using Google’s OAuth 2.0 JavaScript API to perform the OAuth 2.0 end‑user consent and authentication process. This is what gives us the login button and can detect whether we are logged in or not. In order for our website to be authenticated by Google, we need to create an OAuth 2.0 client ID and provide that as the content attribute to this tag, replacing the client-ID placeholder. For instructions on creating a new OAuth 2.0 client ID, see the Appendix at the bottom of this article.
  • <script src="/js.cookie.js"> tag – We need a cookie parser that can extract the identity token from the OAuth 2.0 access token and create a cookie to be sent to the website. The line Cookies.set accomplishes this, using the JavaScript Cookie library, which is included with this tag.

With these pieces in place we now have a public homepage with Google’s login mechanism and a private area protected by NGINX Plus. Note that we didn’t create any content for our private area so a 404 error is to be expected when we try to access it.

Further Reading

For details about advanced JWT functionality, see Authenticating API Clients with JWT and NGINX Plus. It explains how to proxy authenticated requests with user identity information obtained from the JWT, log JWT claims, and support multiple identity providers.

To explore the native JWT support in NGINX Plus, start your free 30‑day trial today or contact us.


Appendix – Creating a Google OAuth 2.0 Client ID

[Editor – We have made every effort to accurately represent the Google APIs GUI at the time of publication, but the GUI is highly dynamic, with menu options and locations subject to change. Use these instructions as a reference and adapt them to the current GUI as necessary.]

  1. Access the Google APIs Dashboard at https://console.developers.google.com/apis/dashboard.

    The page that opens depends on your history with Google APIs. You might have to create an account, accept terms of use, and perform other steps not shown in these instructions.

    The following screenshot shows the upper left corner of the dashboard. Click the word to the right of the Google APIs logo (if you have previously created a project, its name might appear instead of the word Project). Select Create project.

    When creating a Google OAuth 2.0 client ID, select 'Create project' from the drop-down menu next to the Google APIs logo in the upper left corner of the API Manager dashboard.

  2. Create a new project. Here our new project is called NGINX OpenID. After you click the Create button, it can take several seconds before a notification appears indicating your project has been created.

    When creating a Google OAuth 2.0 client ID, specify a name for your new project.

  3. Enable the Google+ API for your project. It provides OAuth 2.0 authentication and identity services.

    (If the API Manager dashboard doesn’t already appear in the main part of the window, click Dashboard in the navigation area on the left of the screen.)

    The first step in enabling the Google+ API is to click the ENABLE API button.

    When creating a Google OAuth 2.0 client ID, while on the API Manager Dashboard screen click the ENABLE API button.

  4. Click Google+ API (in the Social APIs section).

    When creating a Google OAuth 2.0 client ID, select the Google+ API from the list of 'Social APIs' on the Library screen of the API Manager.

  5. Click the ENABLE button.

    When creating a Google OAuth 2.0 client ID, after having selected the Google+ API, click the 'Enable' button.

  6. To create credentials for your project, click Credentials in the navigation area on the left of the screen, then click the Create credentials button.

    Select OAuth client ID on the drop‑down menu.

    When creating a Google OAuth 2.0 client ID, select 'OAuth client ID' as the type of credential to create.

  7. Select the Web application radio button. In the Authorized JavaScript origins field, specify the URL for the host where NGINX Plus is installed and the port number you specified as the parameter to the listen directive in Enabling OpenID Connect for Your Web Application (for example, mydomain.example.com:80). This example uses localhost but your entry needs to be the hostname and port of the actual NGINX Plus instance.

    Click the Create button (you might need to click it more than once to make the creation process start).

    When creating a Google OAuth 2.0 client ID, specify the 'Web application' application type and specify the URL for your NGINX Plus host as an 'Authorized JavaScript origin'.;

  8. The OAuth client window pops up to report your client ID and client secret. Copy the client ID to the content attribute of the <meta name="google-signin-client_id"> tag in your app (replacing the highlighted client-ID placeholder shown above). You do not need the client secret.

    When you have successfully created a Google OAuth 2.0 client ID, it appears in the 'OAuth client' window along with the client secret.

  9. On the main Credentials screen, click OAuth consent screen. Provide your email address and a product name (all other fields are optional).

    When creating a Google OAuth 2.0 client ID, specify your email address and the product name on the 'OAuth consent screen' under API Manager > Credentials.

Return to the section about creating a sample application that uses the credentials

To explore the native JWT support in NGINX Plus, start your free 30‑day trial today or contact us.

Hero image
Are Your Applications Secure?

Learn how to protect your apps with NGINX and NGINX Plus



About The Author

Liam Crilly

Sr Director, Product Management

About F5 NGINX

F5, Inc. is the company behind NGINX, the popular open source project. We offer a suite of technologies for developing and delivering modern applications. Together with F5, our combined solution bridges the gap between NetOps and DevOps, with multi-cloud application services that span from code to customer.

Learn more at nginx.com or join the conversation by following @nginx on Twitter.