Search docs.molo17.com
    Integration guide Security

    Configure single sign-on with OIDC and map identity provider groups to Gluesync roles

    Let people sign in to the Gluesync Control Plane with your company identity provider and receive a Gluesync role from the groups they belong to in that provider. This guide walks through the whole path with Keycloak as the worked example: the client in the provider, the groups claim, the Gluesync OIDC settings, the role mapping, blocked groups, the first sign-in, logout, and a way back in if SSO breaks.

    In this guide

    You will learn how to register Gluesync as a client in the identity provider with the right redirect URIs, make the provider send a groups claim, enter the provider in Gluesync, map groups to roles, block groups, sign in for the first time, check what happened when a sign-in fails, log out so that the provider session ends too, and keep the local admin account as a fallback. A reference section explains why Admin is not in the role list and what is different on Microsoft Entra ID and Okta.

    The examples use a Keycloak realm named gluesync, a client named gluesync, the groups gluesync-managers, gluesync-viewers, and contractors, and two test users named manny and vera. Gluesync is reached at https://localhost:19443: replace it with the address your users open in their browser.

    Quick information

    Goal

    Sign in to Gluesync through your identity provider and get the right role from the provider’s groups

    Audience

    Gluesync administrators and the people who run the identity provider

    Level

    Advanced

    Time required

    About 45 minutes

    Area

    Identity provider → Clients; Control Plane → Settings → Users & access → OIDC configuration

    Applies to

    Gluesync 2.3

    Before you begin

    Make sure that:

    1. You can sign in to the Gluesync Control Plane as the local Super Admin (admin) and you know its password: it is your way back in if SSO is misconfigured;

    2. You have administrator access to the identity provider (the examples use Keycloak);

    3. The identity provider is reachable over HTTPS from the Core Hub container, not only from your browser, and its certificate is signed by a CA that Core Hub trusts (see Optional: trust a private CA otherwise);

    4. You open the Control Plane through the address users will use, for example the address of the reverse proxy in the Gluesync kit: the redirect URI is built from that address;

    5. The groups that should receive access already exist in the provider and contain the right users. In the examples, manny is in gluesync-managers, vera is in gluesync-viewers, and a user named dave is in gluesync-viewers and contractors.

    Do not give an identity provider user the username admin, nor the username of any local Gluesync account you want to keep as it is. The first SSO sign-in of a user whose name matches a local account turns that account into an SSO account and replaces its role with the mapped role. An identity provider user named admin therefore demotes the local Super Admin to the Viewer role.

    Only a Super Admin can save the OIDC configuration. A Manager sees the Users & access section but cannot change the OIDC settings.

    Guide steps

    Register Gluesync as a client in the identity provider

    IdP

    In Keycloak:

    1. Open the realm that holds your users, then open Clients and select Create client;

    2. Set Client type to OpenID Connect, enter the Client ID gluesync, and select Next;

    3. In Capability config, switch Client authentication on and keep Standard flow checked, then select Next;

    4. In Login settings, set Valid redirect URIs to https://localhost:19443/oidc/callback and Valid post logout redirect URIs to https://localhost:19443/ui/v2/login, then select Save;

    5. Optionally set Web origins to https://localhost:19443;

    6. Open the Credentials tab of the client and copy the Client secret.

    Keycloak client settings with the Valid redirect URIs field marked 1 and the Valid post logout redirect URIs field marked 2
    Figure 1. The redirect URI (1) and the post logout redirect URI (2) are the two values Gluesync needs the provider to accept.
    Expected result

    The client exists in the realm. Its Valid redirect URIs holds the exact address <public address of Gluesync>/oidc/callback and its Valid post logout redirect URIs holds <public address of Gluesync>/ui/v2/login.

    Both values must match what Gluesync sends, character for character: scheme, host, port, and path. Behind a reverse proxy, use the public address, including the port if it is not 443. The Gluesync kit publishes Core Hub through Traefik on port 443, so there the address has no port. Gluesync does not have a Signout URL field: after logout it always asks the provider to return the browser to <public address of Gluesync>/ui/v2/login.

    Make the identity provider send the groups

    IdP

    Gluesync reads roles from one claim in the user’s tokens. Keycloak puts realm roles under realm_access.roles, but sends group names only if you add a mapper. Add it to the client:

    1. Open the client, then the Client scopes tab, and select the gluesync-dedicated scope;

    2. Select Add mapper, then By configuration, then Group Membership;

    3. Enter the Name groups and the Token Claim Name groups;

    4. Switch Full group path off;

    5. Keep Add to ID token, Add to access token, and Add to userinfo on, and select Save.

    Keycloak Add mapper form of type Group Membership with the Token Claim Name field marked 1
    Figure 2. Name the claim (1), switch off the full group path (2), and save (3).

    Now check what the provider really sends, before you touch Gluesync:

    1. In the client, open Client scopes, then the Evaluate sub-tab;

    2. Pick a test user in Users, then open Generated ID token.

    Keycloak Evaluate tab for the user manny showing the Generated ID token with a groups claim holding gluesync-managers
    Figure 3. Pick a user (1), open Generated ID token (2), and look for the claim you will use (3).
    Expected result

    The generated token holds a groups array with the group names of the user, for example "groups": ["gluesync-managers"], without a leading /.

    Full group path is on by default in Keycloak. With it on, the token holds /gluesync-managers instead of gluesync-managers, and a Gluesync mapping for gluesync-managers never matches. Switch it off, or write the mapping key with the leading slash (/gluesync-managers, and /Parent/Child for a subgroup).

    Enter the provider in Gluesync

    UI

    1. In the Control Plane, select the Settings gear icon, then Users & access, then the OIDC configuration tab;

    2. Switch Enable OIDC authentication (external identity provider) on;

    3. Enter a Provider name, for example Keycloak: it becomes the text of the sign-in button;

    4. In Issuer URL, enter the base address of the realm, for example https://idp.example.com/realms/gluesync;

    5. In Client ID, enter gluesync, and in Client secret, the secret you copied;

    6. Check Redirect URI (auto-generated): it must equal the Valid redirect URI of step 1. Gluesync fills it from the address in your browser bar, so open the Control Plane through the public address before you save.

    OIDC configuration with the issuer URL marked 1
    Figure 4. Issuer URL (1), Client ID (2), Client secret (3), and the generated Redirect URI (4).
    Expected result

    The four fields are filled. Nothing is saved yet.

    Gluesync reads the endpoints from the provider’s discovery document at <Issuer URL>/.well-known/openid-configuration. Keycloak 17 and earlier include /auth in the realm address (https://idp.example.com/auth/realms/gluesync).

    Tell Gluesync where the groups are and map them to roles

    UI

    1. In Advanced settings, keep Scopes as openid, profile, email;

    2. Set Role claim path to groups, the claim you checked in step 2;

    3. Leave Default role for new users as Viewer: users whose groups match no mapping receive this role;

    4. Under Role mappings, select Add mapping. In OIDC role/group, enter gluesync-managers and set Gluesync role to Manager;

    5. Select Add mapping again, enter gluesync-viewers, and set Gluesync role to Viewer.

    Advanced settings with the Role claim path set to groups and marked 1
    Figure 5. The role claim path (1), the scopes (2), and the default role (3).
    Role mappings with Add mapping marked 1
    Figure 6. Add a mapping (1), then enter the provider group (2) and pick the Gluesync role (3).
    Expected result

    Two mapping rows exist: gluesync-managers to Manager and gluesync-viewers to Viewer.

    Open Gluesync role list in a mapping row showing only the two options Viewer and Manager
    Figure 7. The Gluesync role list offers only Viewer and Manager.

    There is no Admin, Super Admin, or Monitor in this list. Why Admin does not show up explains what to do. The order of the rows matters: when a user belongs to several mapped groups, the first row in the list that matches wins, not the highest role.

    Block groups, save, and test the connection

    UI

    1. In Prevent user access, enter the groups whose members must never get in, separated by commas, for example contractors. Enter * to let in only the users who belong to a group of the role mappings and refuse everyone else;

    2. Select Save OIDC configuration;

    3. Select Test connection.

    Prevent user access with the Denied groups field containing contractors and marked 1 and the Save OIDC configuration button marked 2
    Figure 8. Blocked groups (1) and the Save button (2).
    Save OIDC configuration button next to a green Connection OK result of the Test connection button
    Figure 9. Saved, then Connection OK.
    Expected result

    Saved appears, then Connection OK. Test connection only checks that Gluesync can read the provider’s discovery document and build the sign-in address: it does not exchange a code or read roles, so the first real sign-in is the real test.

    A blocked group is compared with the values Gluesync reads from the Role claim path, the same values the role mappings use. A group that is not in that claim can never block anyone. With the claim path realm_access.roles, the entry contractors blocks nothing, because contractors is a Keycloak group, not a realm role.

    Sign in with SSO for the first time

    UI

    Do this in a private window so that you stay signed in as admin in the other one.

    1. Open the Control Plane sign-in page and select Login with Keycloak (the button shows your Provider name);

    2. On the provider’s page, sign in as a test user, for example manny.

    Gluesync sign-in page with the Login form and a blue Login with Keycloak button marked 1
    Figure 10. The sign-in page gets a second button for the provider (1). The local login form stays.
    Keycloak sign in to your account page with username and password fields
    Figure 11. Gluesync leaves the sign-in page: the user and the password are checked by the identity provider.

    Back in the Control Plane, check the account:

    1. Open Settings, then Account.

    Account info of manny with the username marked 1 and the role Manager marked 2
    Figure 12. The username (1) and the role (2) come from the identity provider.
    Expected result

    The Control Plane opens for manny with the role Manager. Core Hub created the account on this first sign-in. Name and Email stay empty (-): Gluesync does not copy them from the provider.

    Then, as admin, check the account list:

    1. Open Settings → Users & access → Users, and select the OIDC tab under Accounts.

    Accounts list with the OIDC tab marked 1 and the accounts manny with role Manager and vera with role Viewer marked 2
    Figure 13. OIDC accounts appear in their own tab (1) with an OIDC badge and the mapped role (2).

    The role of an SSO account is set again from the provider’s groups at every sign-in, and the role list of these accounts is read-only. Change the role by changing the group membership or the mapping, not in the account list.

    The username comes from the first claim that exists in this order: preferred_username, upn, unique_name, email, sub. If users appear with a long identifier, the provider does not send the claims that carry a readable name: see the Entra ID notes below.

    Check that a blocked group is refused

    UI

    1. Sign out of the private window, select Login with Keycloak again, and sign in as dave, who belongs to gluesync-viewers and contractors;

    2. As admin, open the bell icon, then Open notifications hub, and look for the Unauthorized User entry.

    Gluesync sign-in page with an OIDC error banner reading Access denied: your group membership is not allowed to access this portal
    Figure 14. The sign-in page shows why the sign-in was refused (1).
    Notifications hub with an Error row titled Unauthorized User and the message Access denied: your group membership is not allowed to access this portal marked 1
    Figure 15. Every refusal is also a notification with the same message (1).
    Expected result

    The sign-in page shows OIDC and Access denied: your group membership is not allowed to access this portal. A denied user gets no account. A blocked group wins over a mapping: dave is in a mapped group and is still refused.

    Sessions that are already open are checked too. Gluesync asks the provider about every SSO session on the interval set in Token refresh interval (minutes) (60 by default). When a user was disabled in the provider, was added to a blocked group, or got another role, the session ends at that check and the user must sign in again, which gives the new role.

    Optional: map a group to Monitor with the REST API

    API

    Skip this step if Viewer and Manager are enough. The Control Plane role list does not offer Monitor, but Core Hub accepts MONITOR as the target of a mapping when you save the configuration with the REST API. Replace <core-hub-host> with your Core Hub address and <admin-password> with the password of admin. The commands use jq.

    1. Sign in as admin to get a token:

      TOKEN=$(curl -s -X POST https://<core-hub-host>/authentication/login \
        -H 'Content-Type: application/json' \
        -d '{"username":"admin","password":"<admin-password>"}' | jq -r .apiToken)
    2. Read the configuration, add the mapping, and save it:

      curl -s "https://<core-hub-host>/oidc/configuration?include_secrets=true" \
        -H "Authorization: Bearer $TOKEN" \
        | jq '.roleMappings["gluesync-monitors"]="MONITOR"' \
        | curl -s -X PUT https://<core-hub-host>/oidc/configuration \
            -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d @-
    Expected result

    The call answers OIDC configuration updated. A user in gluesync-monitors signs in with the role Monitor: that user can start, stop, and pause entities but cannot manage users (403 Only super admin or manager can view users).

    The Control Plane cannot show these rows. A mapping to MONITOR or SUPER_ADMIN appears with an empty Gluesync role list, and Save OIDC configuration stays disabled until you remove those rows. Saving from the Control Plane drops them, and it also resets the API-only autoProvisionUsers setting to true. After you add MONITOR mappings with the API, make later changes with the API too.

    Role names in the API are case sensitive and use an underscore: VIEWER, MONITOR, MANAGER, SUPER_ADMIN. A value such as Manager, ADMIN, or SUPER ADMIN is accepted when you save, but at sign-in it falls back to the default role without any error.

    Log out and end the identity provider session

    UI

    1. In the Control Plane, open the user menu in the top bar and select Logout, then confirm Logout in the dialog;

    2. Watch the browser: it leaves for the provider and comes back to the Gluesync sign-in page;

    3. Select Login with Keycloak again.

    Expected result

    Gluesync signs you out, sends the browser to the provider’s logout address, and the provider returns it to <public address of Gluesync>/ui/v2/login. When you select Login with Keycloak again, the provider asks for the password, because its own session ended too.

    How it works, to settle questions about "sessions that stay open":

    • Logout always ends the Gluesync session first, whatever the provider does.

    • For an SSO session, Gluesync then takes end_session_endpoint from the provider’s discovery document and sends the browser there with three parameters: id_token_hint (the ID token issued at sign-in), client_id, and post_logout_redirect_uri (<public address of Gluesync>/ui/v2/login). The address of post_logout_redirect_uri comes from the Origin header of the browser request, or from the Host header if there is none, so the reverse proxy must pass them on.

    • If the provider’s discovery document has no end_session_endpoint, only the Gluesync session ends and the provider session stays open.

    • If the provider does not accept post_logout_redirect_uri, the user stays on the provider’s error page, although Gluesync has already logged them out. Keycloak shows Invalid redirect uri. Register the address in the client, as in step 1.

    You can check the provider’s logout address from a shell:

    curl -s https://idp.example.com/realms/gluesync/.well-known/openid-configuration | jq -r .end_session_endpoint

    Closing the browser tab, or letting the Gluesync session expire, does not log the user out of the provider. Only the Logout button above does.

    Keep the local admin as a fallback

    UI + API

    The local sign-in form stays next to the SSO button, and the local admin account keeps working when SSO is enabled, when the provider is down, and when the OIDC settings are wrong.

    1. To sign in without SSO, enter admin and its password in the form, not the SSO button;

    2. To switch SSO off and later back on without retyping the settings, keep a copy of the configuration with the API first, then save it with enabled set to false:

      curl -s "https://<core-hub-host>/oidc/configuration?include_secrets=true" \
        -H "Authorization: Bearer $TOKEN" > oidc-backup.json
      
      jq '.enabled=false' oidc-backup.json | curl -s -X PUT https://<core-hub-host>/oidc/configuration \
        -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d @-
    3. To switch it on again, send the saved file back:

      curl -s -X PUT https://<core-hub-host>/oidc/configuration \
        -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' -d @oidc-backup.json
    Expected result

    With enabled set to false the sign-in page has no SSO button and the local form works. Sending oidc-backup.json back restores the provider, the mappings, and the blocked groups. The file holds the client secret: store it safely and delete it after use.

    Keep the client secret at hand. Core Hub fills in an empty clientSecret from the stored one only while SSO is on. A PUT that enables SSO with an empty clientSecret after SSO was switched off fails with Client Secret is required when OIDC is enabled, in the Control Plane too: type the secret again.

    Why Admin does not show up in the role list

    The question comes up often: "there is no Admin in the role mapping, is that right?". Three different things are behind it.

    What you expect What Gluesync has

    A role named Admin

    No such role. The roles are Viewer, Monitor, Manager, and Super Admin. Super Admin is the local admin account.

    Admin, Super Admin, or Monitor in the Gluesync role list

    The list offers Viewer and Manager only. A group that should have wide access maps to Manager: a Manager can do everything except manage Super Admin and Monitor accounts, and the user group and Query data access settings.

    A mapping that is not applied

    A group that matches no mapping gives the Default role, which is Viewer. This looks the same as "my Admin group is ignored": see the next table to find out why.

    Core Hub accepts SUPER_ADMIN as the target of a mapping when you save the configuration with the REST API, and a user in that group signs in as a Super Admin who can read the client secret, change or switch off OIDC, and manage every user. The Control Plane does not offer it, and Gluesync does not recommend it. Map the elevated group to Manager, and keep admin as the only Super Admin.

    The next table lists what to check, in order, when a user gets Viewer and should not.

    Check Why it matters

    The claim exists in the provider

    Gluesync cannot map what the provider does not send. In Keycloak use Client scopes → Evaluate → Generated ID token (or Generated access token) and look for the group. If the client lost the roles client scope, realm_access.roles disappears.

    Role claim path points at the claim

    groups for a groups claim, realm_access.roles for Keycloak realm roles, resource_access.<client id>.roles for client roles (escape a dot inside the client id as \.). The default value roles finds nothing in a Keycloak token. A path with a typo, such as realm_access.role, finds nothing either.

    The claim is in one of the three places Gluesync reads

    Gluesync reads the claim from the userinfo response first, then from the ID token, then from the access token, and takes the first place that has a value. Keycloak realm roles are only in the access token and still work.

    The group name matches the mapping key

    The comparison ignores uppercase and lowercase but the whole text must match: manager does not match gluesync-managers, and a space at the end of a key breaks the match. With Full group path on, the token holds /gluesync-managers.

    The order of the mapping rows

    The first matching row wins. A user in a viewer group and a manager group gets the role of whichever of the two rows is first.

    The role names in an API configuration

    MANAGER or VIEWER in capitals. Any other text gives the default role.

    Microsoft Entra ID and Okta

    The steps above stay the same. What changes is the provider side and a few values. This table follows the Gluesync provider pages and the Core Hub code; check each item in your tenant.

    Microsoft Entra ID Okta

    Issuer URL

    https://login.microsoftonline.com/<tenant-id>/v2.0

    https://<your-domain>.okta.com/oauth2/default, or the issuer of your custom authorization server

    Redirect URI

    Register the Gluesync callback address as a Web redirect URI

    Sign-in redirect URI: the Gluesync callback address

    Logout address to allow

    Add <public address of Gluesync>/ui/v2/login as a second Web redirect URI: Entra ID uses these as the allowed post-logout addresses

    Sign-out redirect URI: <public address of Gluesync>/ui/v2/login. Without it Okta refuses post_logout_redirect_uri and the user stays on an Okta error page

    Where the roles come from

    App roles, sent in the roles claim. Set Role claim path to roles and map the Value of each app role, for example gluesync.manager. With Add groups claim, use groups, and map group names or object IDs

    A groups claim added to the ID token of the application. Add groups to Scopes and set Role claim path to groups

    Readable usernames

    Add the email and upn optional claims to the ID token and keep profile and email in Scopes. Without them the account is named after the sub identifier, a long string

    Keep profile and email in Scopes, so that the token carries preferred_username or email for the username

    Okta and the logout request: Gluesync sends id_token_hint, client_id, and post_logout_redirect_uri to the end_session_endpoint of the provider, and there is no Signout URL field to fill. If Okta sessions stay active after Logout, check that the discovery document of your issuer lists an end_session_endpoint, and that the sign-out address above is registered.

    Optional: trust a private CA

    Skip this section if the identity provider uses a certificate from a public CA. If the provider uses a self-signed or private CA certificate, Core Hub must trust it: without that, Test connection fails with a Validator error in the notifications (PKIX path building failed) and sign-in never starts.

    Skip TLS verification in the OIDC settings does not make a self-signed provider work. It lets Core Hub read the discovery document and the user information, but the exchange of the authorization code still checks the certificate, so every sign-in ends with Failed to exchange authorization code. Trust the CA instead.

    To trust the CA, give Core Hub a Java trust store that contains the usual public CAs plus yours:

    1. Copy the trust store out of the Core Hub image: docker cp <core-hub-container>:/usr/lib/jvm/zulu21/lib/security/cacerts ./cacerts;

    2. Add the provider’s certificate: keytool -importcert -alias idp -file idp-ca.crt -keystore ./cacerts -storepass changeit -noprompt. The Core Hub image contains keytool if you have no Java on the host;

    3. Mount the file over the original in the Core Hub service of your docker-compose.yml:

          volumes:
            - ./cacerts:/usr/lib/jvm/zulu21/lib/security/cacerts:ro
    4. Recreate the Core Hub container.

    See Secure database service communication for the other places where Gluesync uses a trust store.

    Verify the result

    You have successfully set up SSO if:

    • The provider client has the exact redirect URI and post logout redirect URI of the public Gluesync address;

    • Test connection answers Connection OK;

    • A test user in a mapped group signs in with the role from the mapping, and appears in Users under the OIDC tab;

    • A user outside every mapped group signs in with the Default role;

    • A user in a blocked group is refused with Access denied: your group membership is not allowed to access this portal;

    • After Logout, the provider asks for the password again;

    • admin can still sign in with the local form.

    Troubleshooting

    Problem Possible cause What to do

    The sign-in page has no SSO button

    OIDC is off, or Issuer URL or Client ID is empty

    Open Settings → Users & access → OIDC configuration, switch it on, and save

    Test connection shows Failed to generate OIDC authorization URL

    Core Hub cannot read <Issuer URL>/.well-known/openid-configuration: a wrong realm or path, a name that Core Hub cannot resolve, or an untrusted certificate

    Open the notification (bell icon, then Open notifications hub): it names the cause, for example 404 Not Found for a wrong issuer, or Validator with PKIX path building failed for a certificate. Fix the Issuer URL, or trust the CA as in the section above

    The provider shows Invalid parameter: redirect_uri (Keycloak) before any sign-in

    The Redirect URI in Gluesync is not in the client’s Valid redirect URIs: scheme, host, port, or path differ, for example http against https, or a missing port behind a reverse proxy

    Copy the address from Redirect URI (auto-generated) into the client, or open the Control Plane through the public address and save the settings again

    The sign-in page comes back with Failed to exchange authorization code

    Wrong Client secret, or the provider certificate is not trusted (Skip TLS verification does not cover this call)

    Paste the secret again from the Credentials tab of the client. For a private CA, trust it as in the section above. The notifications hub holds the same message

    A user gets Viewer although a group is mapped

    The claim is not in the token, the Role claim path is wrong, Full group path is on, the key has other text, or an earlier row matches

    Go through the check table in the section on why Admin does not show up

    Admin or Monitor is not in the Gluesync role list

    The list offers Viewer and Manager only

    Map the group to Manager. For Monitor, use the REST API as shown in the optional step

    A blocked group does not block anyone

    The group is not in the claim that the Role claim path reads, for example a Keycloak group with the path realm_access.roles

    Use a claim that carries the group, such as groups, or block a realm role instead

    A user in a blocked group is still in the account list

    Blocking refuses sign-ins. It does not delete accounts that exist

    Delete the SSO account in Settings → Users & access → Users if you want it gone

    A local user was converted to an SSO user and lost the role

    The identity provider has a user with the same username

    Rename the provider user, or delete the local account before the first SSO sign-in. Use a Super Admin to set the role back if the account was a local Manager

    The user still has the old role after a change in the provider

    The Gluesync session has not been checked yet

    Wait for the next check (Token refresh interval (minutes), 60 by default) or ask the user to log out and sign in again

    After Logout the user is still signed in at the provider, or an Okta session stays active

    The provider has no end_session_endpoint, the session was not started by SSO, or the browser never followed the logout address

    Check the discovery document as shown in the logout step. Use Logout from the Control Plane, not the browser’s close button

    After Logout the browser stays on a provider error page

    <public address of Gluesync>/ui/v2/login is not in the provider’s list of post logout or sign-out addresses

    Add that exact address, with the path, to the client (Valid post logout redirect URIs in Keycloak, Sign-out redirect URI in Okta, Allowed Logout URLs in Auth0, a Web redirect URI in Entra ID)

    SSO signs in, but the Control Plane shows an error for a new user

    autoProvisionUsers is false in an API configuration, so the account was not created

    Switch it on again with the API, or create the account in Users first. The Control Plane does not show this setting

    Contact MOLO17 Support if you need assistance with single sign-on.