Managing extensions

You can define your own extension scripts in order to modify the authentication context after the user authenticates themselves to autorize the client application. Complementary to the scripts, you can also create secrets in order to use them within scripts or to validate policies.

Extensions in a nutshell

ACP allows you to write JavaScript extension scripts in a convenient embedded environment so that you can modify the ACP authentication context. Once written, you can enable the scripts on individual IDPs so that they are executed after user authentication. For example, scripts can be useful for the following use-cases:

  • Pulling data (such as user permissions) from external systems

  • Overwriting static attributes in the authentication context

All extension code is executed independently in a secured environment following best security practices. You can test the code using the provided testing and debugging tools and execute it in a sandbox environment available out of the box.

In addition to scripts, you can create secrets and use them for the following purposes:

  • To safely store confidential information within ACP

  • To access protected resources from within your scripts

  • To validate policies in your authorization server

Secrets represent any information that you want to keep confidential. They are encrypted after creation, meaning that their value cannot be retrieved in any way outside of a scripted function or a policy validator.

Prerequisites

  • Access to an ACP tenant. For testing purposes, make sure that Sandbox IDP and Demo Application are set up. For more information, see Adding new workspace in ACP.

  • Working knowledge of JavaScript

  • Authentication context is defined. For testing purposes, add authorized_clients (list of strings) and static_attribute (string) to your authentication context.

  • Claims to be issued are mapped to authentication context attributes affected by your script. For testing purposes, make sure that authorized_clients and static_attribute are issued as claims in the Demo Application.

Create an extension

The video below shows how to create scripted extensions in ACP based on the out-of-the-box templates.

Note

To remove or rename an extension, use the contextual hover-on menu available for each extension in the EXTENSIONS list.

  1. Go to Extensions from the workspace main page.

  2. Create an extension using one of the available menu options

    • + - creates an empty script.

    • Sample api request - creates a script with code executing a request to a given URI.

    • Sample with secret - creates a script returning a secret.

    • Sample authn context modification - creates a script which modifies the authentication context after it’s prepared by ACP.

  3. Enter the script name in the form and click Create. Your script is created and opened in the embedded editor.

  4. Write or modify your script in the editor.

  5. Save your script.

  6. Run the script in test mode to check if it works as expected. In the video below, we are checking a simple script returning a secret value.

    1. Check the data in the INPUT section. It is meant to mimic a real request processed by ACP. Modify the paremeters if necessary for the purpose of your test.

    2. Select Run test.

      Result

      Your script runs against the input data. The result is printed in the OUTPUT section. Runtime information is printed in the CONSOLE section.

      In a real world scenario, attribute values from OUTPUT override the original authentication context (provided they exist in the authentication context - new attributes are NOT created).

  7. Optionally, proceed to testing the script with the Sandbox IDP based on the provided template, showing how to combine an API request with a modification of the authentication context.

Test the extension with the Sandbox IDP

Test the extension script using the Sandbox IDP in your workspace. For the purpose of this test, use the code below as a template to make a call to a target resource (under uri) and modify the authentication context based on data in the response. Note that all code is within the function scope - it’s a requirement in ACP scripts. In order to work end-to-end, the below script requires the following configuration in ACP:

module.exports = async function(context) {
const request = require('request-promise-native');
try {
  const response = await request({
    method: 'GET',
    json: true,
    uri: 'http://example.com/resource/path'
  });

  return {
      authn_ctx: {
        authorized_clients: response.find(x => x.userId == context.authn_ctx.given_name).authorizedClients.map(x => x.name),
        static_attribute: 'static_value'
      }
    };
}
catch(e) {
   console.error(e);
 }
}
Attribute Description
context Represents the entire function input. Always contains the authn_ctx and secrets objects.
authn_ctx Your main object of interest. This object represents the authentication context and is always passed as the function input. Refer to it via context.authn_ctx.ATTRIBUTE_NAME. All attribute values written into authn_ctx by your script replace thvalues from the original authentication context. Attribute to be overwritten must be defined in the ACP authentication context - you cannot create new attributes using the script. Please check the authentication context definition in your ACP workspace if you’re not sure which attributes are defined.
secrets This object represents ACP secrets. Refer to it via context.secrets.SECRET_NAME. You can find secret names in the Secrets section.

The above script compares the given_name in the authentication context against the userId in the target JSON record. When they match, the script writes the underlying authorizedClients.name parameter into the authorized_clients authentication context object. Additionally, the script sets the static_attribute in the authentication context to static_value. ACP can, therefore, issue claims mapped to the modified authorized_clients and static_attribute attributes.

  1. Enable the script in the Sandbox IDP. Go to Identities -> Sandbox IDP -> Mappings and select the script from the Post authentication script list.

  2. In Identities -> Sandbox IDP -> Mappings, map the name IDP attribute to the given_name context attribute.

  3. Add authorizedClients (list of strings) and static_attribute (string) to your authentication context.

  4. Add the authorizedClients and static_attribute claims to your workspace. Map them to the corresponding attributes defined in the previous step. Assign the profile scope to both claims. For more information, see Configuring claims for ID tokens and access tokens.

  5. To simulate external data, add the following object to an online sharing tool (such as hastebin):

    Note

    Make sure that userId matches an existing user name in the Sandbox IDP user pool.

    [
      {
          "userId":"SANDBOX_USER_NAME",
          "partnerDetails":{
            "orgId":"001",
            "partnerId":"001",
            "partnerType":[
                "third-party-access"
            ]
          },
          "authorizedClients":[
            {
                "name":"Client 1",
                "privileges":[
                  "tpa-access"
                ]
            },
            {
                "name":"Client 2",
                "privileges":[
                  "tpa-access"
                ]
            },
            {
                "name":"Client 2",
                "privileges":[
                  "tpa-access"
                ]
            },
            {
                "name":"Client 4",
                "privileges":[
                  "tpa-access"
                ]
            }
          ]
      }
    ]
    
  6. Add the path to the above resource to the uri parameter in your script.

  7. Log in to the demo application as the user you entered in the userId attribute above.

    Result

    In case of the sample script used for this test , we can expect the authorized_clients and static_attribute claims to be modified. Inspect the ID token presented after login to confirm this:

    {
    "acr": "0",
    "aid": "default",
    "amr": [
        "pwd",
        "mfa"
    ],
    "aud": "default-demo",
    "auth_time": 1633442410,
    "authorized_clients": [
        "Client 1",
        "Client 2",
        "Client 3",
        "Client 4"
    ],
    "email": "mail@domain.com",
    "exp": 1633446013,
    "given_name": "SANDBOX_USER_NAME",
    "iat": 1633442413,
    "idp": "c5dh64n3qv46ahmfntq0",
    "iss": "https://tenant.authz.cloudentity.io/tenant/default",
    "jti": "88c8cb95-a826-41c1-8e55-c2508745d593",
    "name": "Joe",
    "nbf": 1633442413,
    "nonce": "c5e5klpli7m52gnpk300",
    "rat": 1633442413,
    "scp": [
        "email",
        "openid",
        "profile"
    ],
    "static_attribute": "static_value",
    "st": "public",
    "sub": "12539980",
    "tid": "cloudentity-tenant"
    }
    

Recommendations for writing extensions

Please keep in mind that if your script fails, users won’t be able to autheticate. Adhere to the following best practices when writings scripts:

  • Write safe code using try/catch statements.

  • Add meaningful error messages.

  • Run your script in test mode at least once.

When running the script in test mode, check for errors in the console. You can see a sample error report in the video below, where we’re making a call to a non-existing document.

Create a secret

ACP allows you to define secrets which can be used in JavaScript function calls and policies. The video below shows how to add and manage secrets.

  1. Go to Extensions in the left-hand menu. The Extensions page opens.

  2. Select Create Secret. Provide the secret name and value in the pop-up window when prompted.

    Note

    You won’t be able to see the secret value after it’s saved. It can be only retrieved by an extension script or a policy validator.

  3. Select Create. Your secret is added to the list.

You can manage your secrets from the workspace settings page. Go to Settings -> Secrets to edit secret values, delete secrets, or create new secrets.

Use secret in extension

To use your secret in an extension script, provide the secret name within a function via the context.secrets.SCRIPT_NAME reference:

module.exports = async function(context) {
    return {
          secret: context.secrets.SCRIPT_NAME
    };
}

Such reference is ready out of the box if you create a script from the Sample with secret template.

Use secret in a policy

To use your secret in Cloudentity policy editor, refer to it in a policy validator by selecting Secrets as the source or target and providing the secret name. The secret value is then used for comparison in the validator. For more information, read Creating a policy in Cloudentity editor.

To use your secret in a Rego policy, see Rego secret check policy.