Auth0

Auth0 provides authentication and authorization as a service. For small projects that need to manage a user base but are concerned about security issues associated with local user credentials, Auth0 can offload the responsibility of managing a local datastore to Auth0. This capability is free for up to 7000 users (or unlimited users for open-source projects willing to display an Auth0 badge on their page). Auth0 manages the user accounts, and project clients can fetch user attributes using standard OAuth2/OIDC protocols.

CILogon can be added as a "custom social connection" to Auth0, enabling users to log in with their university identity provider through CILogon. This document describes how to register a new Auth0 OAuth2/OIDC client and how to connect CILogon as a custom social connection.

The first step is to sign up for an Auth0 account. After verifying your account, you should log in and be directed to the Dashboard. Here is where you will create a new application and connect CILogon as a social connection.

Click the "Create Application" button.

On the Create Application page, enter a name for your application (e.g., "My Test App") and select "Regular Web Applications" for the application type. Then click the "Create" button.

Your new application will be created and you will be shown the Quick Start page. Click the "Settings" tab.

On the settings page, you should see the important parameters which will be needed when configuring this Auth0 application with your local OAuth2/OIDC client. Note the following configuration settings for later use.

  • Domain (Also required when registering this Auth0 client with CILogon)
  • Client ID
  • Client Secret (You will need to click the "Reveal client secret" check box to view this value)

Scroll down the page a bit until you see "Allowed Callback URLs". In this text box, enter the callback URL for your OAuth2/OIDC client. Using the mod_auth_openidc example, this corresponds to the "redirect" directory under the "oidc" directory where your application will extract the user attributes. You will need this URL when registering the Auth0 application with CILogon.

Scroll to the bottom of the page and click the "Save Changes" button.

Now you can register this Auth0 application with CILogon. Go to https://cilogon.org/oauth2/register and fill in the requested information. The important configuration is the Callback URL. This value is formed from the "Domain" value for the Auth0 application followed by "/login/callback". Also be sure to select Scopes "email", "profile", and "org.cilogon.userinfo" in order to get additional user attributes from CILogon.

After you click the "Register Client" button, you will be shown a new Client ID and Client Secret. RECORD THESE VALUES. The Client Secret will not be shown to you again. Your client registration request is not active until it has been approved by CILogon Administrators. The CILogon Client ID and Client Secret will be used on the Auth0 site when configuring CILogon as a "custom social connection".

Back on the Auth0 Dashboard, click the "Extensions" link in the left column. On the Extensions page, enter "custom" into the search field to quickly locate the "Custom Social Connections" extension. You will be prompted to install the extension. (In the screenshot below, the extension has already been installed.) Once, installed, it will appear in the "Installed Extensions" tab.

Click on the "Custom Social Connections" button to bring up the Custom Social Connections page in a new tab/window. Click the "New Connection" button.

On the "New Connection" page, enter configuration as shown below.

  • Name: CILogon
  • Client ID: the Client ID you got when you registered your CILogon client
  • Client Secret: the Client Secret you got when you registered your CILogon client
  • Authorization URL: https://cilogon.org/authorize
  • Token URL: https://cilogon.org/oauth2/token
  • Scope: openid email profile org.cilogon.userinfo
  • Fetch User Profile Script:
function(accessToken, ctx, callback) {
  'use strict';

  const jwt = require('jsonwebtoken');
  if (!ctx.id_token) return callback('missing-id_token');
  const id_token = jwt.decode(ctx.id_token);
  if (!id_token) return callback('malformed-id_token');
  if (!id_token.sub) return callback('missing-sub');

  const profile = {
    user_id: id_token.sub,
    email: id_token.email,
    name: id_token.name,
    given_name: id_token.given_name,
    family_name: id_token.family_name,
    idp: id_token.idp,
    idp_name: id_token.idp_name,
    eppn: id_token.eppn,
    eptid: id_token.eptid,
    oidc: id_token.oidc,
    affiliation: id_token.affiliation,
    ou: id_token.ou,
    member_of: id_token.member_of,
    cert_subject_dn: id_token.cert_subject_dn,
    acr: id_token.acr,
    entitlement: id_token.entitlement,
    itrustuin: id_token.itrustuin
  };

  if (!id_token.name) {
    profile.name = id_token.given_name + ' ' + id_token.family_name;
  }

  return callback(null, profile);
}

Scroll to the bottom and click the "Save" button.

Click on the "Apps" tab and make sure that the green toggle button is on for "My Test App". Then click the "Save" button. Then click the little Circle X in the upper right corner to close this popup window.

Auth0 asserts only the basic user profile (e.g., names) and email claims to clients. This means CILogon user attributes such as ePPN (eduPersonPrincipalName) do not pass through automatically. However, it is possible to assert CILogon attributes in special Auth0 attributes by using a custom "Rule".

Back in the Auth0 Dashboard page, click the "Rules" link in the left column. Then click the "Create Rule" button.

You will be shown the "Pick a rule template" page. Click the "Empty rule" button.

On the "Edit Rule" page, enter the following values.

  • Name: CILogon Namespaced Claims
  • Script:
function (user, context, callback) {
  const namespace = 'https://cilogon.org/';
  if (user.idp) context.idToken[namespace + 'idp'] = user.idp;
  if (user.idp_name) context.idToken[namespace + 'idp_name'] = user.idp_name;
  if (user.eppn) context.idToken[namespace + 'eppn'] = user.eppn;
  if (user.eptid) context.idToken[namespace + 'eptid'] = user.eptid;
  if (user.oidc) context.idToken[namespace + 'oidc'] = user.oidc;
  if (user.affiliation) context.idToken[namespace + 'affiliation'] = user.affiliation;
  if (user.ou) context.idToken[namespace + 'ou'] = user.ou;
  if (user.member_of) context.idToken[namespace + 'member_of'] = user.member_of;
  if (user.cert_subject_dn) context.idToken[namespace + 'cert_subject_dn'] = user.cert_subject_dn;
  if (user.acr) context.idToken[namespace + 'acr'] = user.acr;
  if (user.entitlement) context.idToken[namespace + 'entitlement'] = user.entitlement;
  if (user.itrustuin) context.idToken[namespace + 'itrustuin'] = user.itrustuin;
  callback(null, user, context);
}

Scroll to the bottom and click the "Save Changes" button.

You should see that the rule has been Saved Successfully. Click the "Back to Rules" link near the top.

Back on the Rules page, make sure the green toggle button is enabled for the "CILogon Namespaced Claims" rule.

Optionally, we can configure this client to allow JUST CILogon and not any username/password Auth0 authentication. Click the "Applications" link in the left column, then click "My Test App". Click the "Connections" tab and make sure the "Username-Password-Authentication" green toggle button is off.

Also optionally, we can configure the Login box to show the CILogon icon. This is a bit more work and simply modifies the UI a bit. Click the "Universal Login" link in the left column. Then click the "Login" tab. Make sure the "Customize Login Page" toggle button is green.

Scroll down and look for a "theme" block in the "new Auth0Lock()" function. Add the following code in the "theme" block so it looks like the screenshot below.

        authButtons: {
          "CILogon": {
            displayName: "CILogon",
            primaryColor: "#4b794b",
            foregroundColor: "#fff",
            icon: "https://cilogon.org/images/cilogon-logo-40x40-b.png"
          },

Then scroll to the bottom and click the "Save Changes" button.

Finally, we are ready to configure the local OAuth2/OIDC client to use Auth0 and CILogon for authentication. One again using the mod_auth_openidc example, enter the Client ID and Client Secret from the "My Test App" Settings page.

OIDCProviderMetadataURL https://dev-83o7yuaf.auth0.com/.well-known/openid-configuration
OIDCProviderIssuer https://dev-83o7yuaf.auth0.com/
OIDCClientID "MY TEST APP CLIENT ID COPIED FROM AUTH0 SETTINGS PAGE"
OIDCClientSecret "MY TEST APP CLIENT SECRET COPIED FROM AUTH0 SETTINGS PAGE"

OIDCCryptoPassphrase ThisIsARandomPassphraseCHANGEIT
OIDCRedirectURI https://example.org/oidc/redirect
OIDCScope "openid profile email"

<Location /oidc/>
   AuthType openid-connect
   Require valid-user
</Location>

After adding the sample PHP code and navigating to it (e.g., https://example.org/oidc/index.php), you should see a JavaScript-based popup box to "Log In with CILogon".

Click the "Log In With CILogon" button to be redirected to CILogon and select your Identity Provider (IdP).

After authenticating with your IdP, you will be shown the HTTP environment variables that were set by mod_auth_openidc.

OIDC_CLAIM_aud                                 m56ZrkDBAcFx08wcLETjk3bcTYgp1oyd
OIDC_CLAIM_email                               jsmith@illinois.edu
OIDC_CLAIM_exp                                 1570505456
OIDC_CLAIM_family_name                         Smith
OIDC_CLAIM_given_name                          John
OIDC_CLAIM_https---cilogon_org-acr             urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
OIDC_CLAIM_https---cilogon_org-affiliation     employee@illinois.edu;member@illinois.edu;staff@illinois.edu
OIDC_CLAIM_https---cilogon_org-cert_subject_dn /DC=org/DC=cilogon/C=US/O=University of Illinois at Urbana-Champaign/CN=John Smith A12345
OIDC_CLAIM_https---cilogon_org-entitlement     urn:mace:dir:entitlement:common-lib-terms
OIDC_CLAIM_https---cilogon_org-eppn            jsmith@illinois.edu
OIDC_CLAIM_https---cilogon_org-eptid           urn:mace:incommon:uiuc.edu!https://cilogon.org/shibboleth!Gj39Sj49Gj39j93jSj39yg=
OIDC_CLAIM_https---cilogon_org-idp             urn:mace:incommon:uiuc.edu
OIDC_CLAIM_https---cilogon_org-idp_name        University of Illinois at Urbana-Champaign
OIDC_CLAIM_https---cilogon_org-itrustuin       654321987
OIDC_CLAIM_iat                                 1570469456
OIDC_CLAIM_iss                                 https://dev-83o7yuaf.auth0.com/
OIDC_CLAIM_name                                John A Smith
OIDC_CLAIM_nickname                            jsmith
OIDC_CLAIM_nonce                               mwGG-Qkhyvyha09o8v2nQ6E7qCbSDrrqeMPQOohP8Xo
OIDC_CLAIM_picture                             https://s.gravatar.com/avatar/3868276918695482848692759847865?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Ftg.png
OIDC_CLAIM_sub                                 oauth2|CILogon|http://cilogon.org/serverA/users/12345
OIDC_CLAIM_updated_at                          2019-10-07T17:30:29.692Z
OIDC_access_token                              DJQhcRAG3i9m9349gjWJwHnXpg5szD9
OIDC_access_token_expires                      1570555857

Some explanation of the various attributes coming from Auth0 is in order. Internally, Auth0 automatically creates a new user account for users logging in with Custom Social Connections. The user_id for these accounts is formed as "oauth2|CONNECTION|CONNECTION_USER_IDENTIFIER". In the case of CILogon, this means that the "sub" (OIDC_CLAIM_sub above) is set to "oauth2|CILogon|http://cilogon.org/ServerX/users/XXXXX" where the part after the last "|" (vertical bar) is the unique user identifier for the CILogon user. So if your application wants to use the CILogon user id, it needs to strip off the extra prefix added by Auth0.

As stated earlier, the only user attributes that are asserted by Auth0 are the names and email claims as requested by the "profile" and "email" scopes. So you see above that "family_name", "given_name" and "name" values all transferred from CILogon to Auth0 to the client in the usual OIDC claims.

The additional user attributes as requested by the "org.cilogon.userinfo" scope come through in the special "https---cilogon_org-" scoped values. This is handled by the special "CILogon Namespaced Claims" Rule entered earlier. So again your application will need to perform some post-processing of these claim names to strip off "https---cilogon_org-" in order to get the actual claims asserted by CILogon.