Embedding Auth-Only Connections

How Do Auth-Only Connections Work?

Pandium offers an Auth-Only Connection offering that allows you to build out a custom, configure-less (to the user), embedded page into your system that allows users to login directly to different systems, and automates the integration installation process for users, without them ever seeing Pandium. This page is displayed in an iframe within a web app that sits behind your company login.

This can be useful to create your own area in your site where you dictate certain connectors/integrations that users can connect to, and providing them with a simple path to authenticate into a system and have integrations installed without further work.

In order to maintain the security of your user's data, you must stand up a backend service that redirects to the Auth-Only Connection page with user information encoded in a JSON Web Token (JWT).

Difference Between In-App Marketplace and Auth-Only Connections

While similar to Pandium's In-App Marketplace, there are key differences between the two features:

The In-App Marketplace provides a more holistic marketplace experience, where you can show various integration options and app detail data to both potential and existing users, and provide them directed workflows to set configurations, schedules, and install apps manually.

With Auth-Only Connections, you can simplify this process through background connect, i.e. users are automatically authenticated to your system when connecting apps, and immediately directed to authenticate into the external system with no configuration requirements needed by the user.

This is accomplished by first, defining what systems you even want to display to users on this page through the JWT, and second, setting specific configuration fields in the JWT.

Learn more about the process for setting up Auth-Only Connections below.

Embedding Auth-Only Connection Page

Before your site can be enabled for SSO via JWT with Pandium, you will need to reach out to the Pandium support and exchange the below:

  • A shared secret supplied by Pandium. This is used to sign the JWT, and helps Pandium ensure the requests come from you and you alone.

  • If embedding a Pandium Marketplace in your application, we'll also need the domain of the application that will serve as the iframe's parent. Pandium needs this for CORS purposes.

    • Note: If you are using a Sandbox or PoC environment, we will not need the domain.

Configuring the Auth-Only Experience

Each system that you are surfacing to your users will need to direct to a specific URL where your users can authenticate. The URLs will look like the below:

If using a Sandbox account, the URL will be: https://emp.sandbox.pandium.com/orgname/connector/auth?tenant={jwt}

If using a production account, the URL will be:

https://emp.pandium.io/orgname/connector/auth?tenant={jwt}

In these URLs, the organization name is your unique company name, which can be found in the URL while logged into the Integration Hub URL, e.g. https:/imp.sandbox.pandium.com/yourcompanyname?tenant=, and the specific Connector name being used, which can be found in integration the object via our API.

Additionally, within the JWT, each connection will need to have fields defined in the 'xti' field in your JWT. as seen below in the example with a connector named 'gwt' and integration named 'gwt2hs':

"xti": {
    connector_name: "gwt",
    integration_name: "gwt2hs",
    token: "some token"
}

For Auth Dialog to function, the JWT will require a token parameter on your side for your organization's connector, so that when users connect, they are able to authenticate into your system.

For information on setting the backend service that enables JWT functionality, check out the below example:

Setting up the JWT and Backend Service

To setup the JWT and backend services needed to enable your marketplace or auth-only features, take a look at the below:

Framework of a Sample Backend Service in Python

This is an example of setting up the service you'll need to enable this in Python:

import time
import uuid

import falcon
from jwt import encode


class PandiumSSOJWTEndpoint:
    def __init__(self, config):
        self.config = config

    def on_get(self, req: falcon.Request):

        payload = {
            'iat': int(time.time()),
            'jti': str(uuid.uuid4()),
            'external_id': '',  # Not Required. Add this if the unique id you use for your user is not the same as email address
            'meta': '',  # Not Required. Free form object to associate with your user in Pandium
            'sub': '',  # Required. Email address of your user. Pandium uses this to link our tenant to your user's account in your system
        }

        jwt = encode(payload, self.config['PANDIUM_SHARED_SECRET'], algorithm='HS256')
        sso_url = f"https://emp.pandium.com/{self.config['ORG_NAME']}/connector/auth?tenant={jwt}"

        raise falcon.HTTPTemporaryRedirect(sso_url)


app = falcon.API()
app.add_route('/pandium-sso', PandiumSSOJWTEndpoint({'PANDIUM_SHARED_SECRET': '', 'ORG_NAME': ''}))

Creating the Signed JSON Web token

You will need to build a JWT containing the users’ data in a backend service.

JWTs are made of 3 parts separated by a period (.). Each piece is base64Url encoded which then gets assembled to look like below:

<base64url-encoded header>.<base64url-encoded payload>.<baseurl-encoded signature>

Pandium currently supports the following header:

{
    "alg": "HS256",
    "typ": "JWT"
}

The base64url-encoded version of the above is below:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

{
 "iat": 1621521641,
 "jti": "1cfa7dbf-8110-4237-ad22-410608791b7d",
 "ti": {
   "udn": "Pandium Test",
   "ufn": "Important Person",
   "uem": "test@pandium.com",
   "ili": [
     "new-id",
     "something-different"
   ],
   "aid": "",
   "adn": "",
   "xti": {
     "extraProp": "extra value",
     "extraList": [
       "val1",
       "listVal"
       ]
     "connector_name": "gwt",
     "integration_name": "gwt2hs",
     "token": "your token"
   }
 },
 "sub": "test-pandium-com"
}

Signature:

The JWT signature is produced by concatenating the Base64url encoded header with the Base64url encoded claims, and then signing using the shared secret using HMAC with SHA-256.

HMAC-SHA256(base64url-encoded(header) + "." + base64url-encoded(payload)), <shared secret>)

A Complete Example.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
    .eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
    .SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

iFrame Post Message

Once the user successfully connects via the auth dialog we will send a postMessage from the iframe window which your application can then use to track the user's state. The event will have tenant data as well as a webhook url you can use to register webhooks for the tenant in your system. This can be used if you don't have a backend endpoint we can register webhooks with during connect.

Example MessageEvent:

"data": {
    "message": "pandium-success",
    "webhook_url": "https://api.pandium.io/v1/webhooks/{tenant specific webhook hash}",
    "tenant": {
        "archived": false,
        "name": "test-tenant",
        "namespace": "staging-gwt",
        "configs": {},
        "created_date": "2024-03-11T18:45:41.532727",
        "paused": false,
        "user_schedule": "*/30 * * * *",
        "schedule": "8-59/30 * * * *",
        "source": "admin",
        "integration": {
            "id": 1,
            "name": "test-integration"
        },
        "integration_release": null,
        "integration_release_channel": "Default",
        "id": 11,
        "modified_date": "2024-03-11T18:45:41.532729",
        "connected_users": {
            "pandium": {
                "id": "112fd91d-e197-4910-8da3-8c7174934d2f",
                "email": "test@pandium.com",
                "username": "test-pandium-com",
                "attributes": {
                    "jwt": {
                        "display_name": "Pandium Test",
                        "full_name": "Important Person",
                        "external_integrations": "some-int",
                        "auditable_uid": "1800",
                        "auditable_display_name": "Auditable Person",
                        "extra_tenant_info": "{\"extraProp\":\"extra value\",\"extraList\":[\"one\",\"listVal\"],\"connector_name\":\"test-connector\",\"integration_name\":\"test-integration\",\"token\":\"some-token\"}",
                        "namespace": "staging-gwt",
                        "keycloak_uri": "authz.nc.pandium.io"
                    }
                },
                "first_name": null,
                "last_name": null,
                "email_verified": true,
                "enabled": true,
                "realm_id": "staging-gwt",
                "created_timestamp": 1709151776419
            }
        },
        "status": {
            "tenant_id": 11,
            "last_run": {},
            "current_run": {},
            "last_successful_run": {},
            "dynamic_configs": {},
            "auth": {
                "connected": true,
                "TEST_AUTH_STATUS": "Connected",
                "TEST_LAST_CHANGE": "2024-03-15T14:04:02.96Z",
                "GWT_AUTH_STATUS": "Connected",
                "GWT_LAST_CHANGE": "2024-03-15T14:04:02.05Z"
            }
        }
    }
}

Last updated