Skip to content
Menu
Search
Browse documentation & this page

Developer Guide

Single sign-on for the CMS

Let your editors sign in to /cms with Microsoft Entra, Okta, Auth0 or any OpenID Connect provider, with their access set by the groups they belong to there.

Out of the box, people sign in to /cms with an email address and a password that Cendia stores. With single sign-on, they can sign in with the account they already have at work instead: the sign-in page offers Sign in with Microsoft (or whatever you call it) below the password form.

Cendia speaks OpenID Connect, the standard behind Microsoft Entra, Okta, Auth0, Ping, Keycloak and Google Workspace. This guide walks through Microsoft Entra step by step, then says what differs for the others.

The short version: register an app with your provider, turn on its groups claim, put three values and your group mappings in configuration, and keep a password administrator as a way back in. No code changes are needed.

How it decides who gets in

Access comes from the person's groups at the provider, mapped to Cendia's groups in your configuration:

Rule What it means
Only mapped groups get in A person must be in a provider group you mapped to Administrator or Author. Anyone else is refused, and no account is made for them. Mapping a group only to one of your own Cendia groups (say Marketing) admits nobody on its own.
The provider's groups replace the person's At every sign-in, the person's Cendia groups are set to exactly the ones their provider groups map to. Take someone out of a group at the provider and the access it gave goes away at their next sign-in.
An existing account is linked by address If a Cendia account already uses the person's address, the first sign-in links it. From then on it signs in through the provider only, and its password is removed. Their history (versions, tasks, the activity report) stays with them.
There is always a way back in The password form never goes away, and Cendia refuses to link the last administrator who signs in with a password. If the provider is down, or a mapping is wrong, that administrator can still sign in.
Locked out means locked out An account locked under Settings › Users can't sign in through the provider either.

The mappings live in configuration, not in the CMS, on purpose: who may administer your CMS is a deployment decision, made by whoever controls the server's settings.

Set it up with Microsoft Entra

You'll need to be able to create app registrations and groups in your Entra tenant. Do these steps in order; each one gives you something the next one needs.

1. Register the app

  1. Go to entra.microsoft.com and open Identity › Applications › App registrations. Click New registration.

  2. Name: anything your administrators will recognise, such as Cendia CMS.

  3. Supported account types: Accounts in this organizational directory only (single tenant).

  4. Redirect URI: choose Web, and enter your site's address followed by /cms/signin-oidc:

    https://www.example.com/cms/signin-oidc
    
  5. Click Register.

The redirect URI is where Entra sends the browser back after sign-in, and it has to match exactly. Add one for every address the CMS is reached on: the production host, a staging host, and http://localhost:5081/cms/signin-oidc (or your own port) for local development. Entra accepts plain http only for localhost. To add more later, open the app's Authentication page.

2. Copy two IDs

The app's Overview page shows:

  • Application (client) ID
  • Directory (tenant) ID

Neither is a secret. They go in appsettings.json in step 6.

3. Create a client secret

  1. Open Certificates & secrets and click New client secret.
  2. Give it a description and an expiry, and click Add.
  3. Copy the Value column, not the Secret ID. Entra shows it only once.

This one is a secret. It never goes in appsettings.json; step 6 shows where it does go.

Note the expiry date. When the secret expires, sign-in through Entra stops working (people are sent back to the sign-in page with a message) until you create a new one and update the setting. The password form keeps working throughout.

4. Send group membership in the sign-in

  1. Open Token configuration and click Add groups claim.
  2. Tick Security groups.
  3. Leave ID, Access and SAML on Group ID, and click Add.

Without this, Entra doesn't say which groups the person is in, and every sign-in is refused.

5. Create the groups

Create a security group for each kind of access you want to give. Most installations need two:

  1. Open Identity › Groups › All groups and click New group.
  2. Group type: Security. Group name: for example Cendia Administrators.
  3. Add the people who should have that access as Members, and click Create.
  4. Open the group and copy its Object ID.

Repeat for Cendia Authors. Cendia identifies a group by its Object ID, not its name, so renaming a group in Entra later changes nothing.

6. Configure the site

In appsettings.json, with your two IDs from step 2 and the Object IDs from step 5:

{
  "Cendia": {
    "Oidc": {
      "Enabled": true,
      "DisplayName": "Microsoft",
      "Authority": "https://login.microsoftonline.com/<tenant-id>/v2.0",
      "ClientId": "<client-id>",
      "GroupMappings": {
        "<object-id-of-Cendia-Administrators>": [ "Administrator" ],
        "<object-id-of-Cendia-Authors>": [ "Author" ]
      }
    }
  }
}

A provider group can map to several Cendia groups, which is how you give people one of your own groups as well as their role:

"<object-id-of-Marketing-Team>": [ "Author", "Marketing" ]

The client secret from step 3 goes in user-secrets on your own machine:

dotnet user-secrets set "Cendia:Oidc:ClientSecret" "<secret value>"

and in an environment variable on a hosted site:

Variable Value
Cendia__Oidc__ClientSecret The secret value from step 3

The double underscore is how .NET spells : in an environment variable. Restart the site after changing any of these settings.

7. Keep a way back in

Before anyone signs in through Entra, make sure the CMS has an administrator who will keep signing in with a password, and that it is not an address anyone will use with Entra. For example:

  1. Sign in with your password as you do today.
  2. Under Settings › Users, add a user such as [email protected] with a strong password and the Administrator role. Store the password somewhere your team can reach in an emergency.

If you skip this and your own password account is the only administrator, Cendia refuses to link it the first time you sign in through Entra, and tells you to create another administrator first.

8. Check it

  1. Sign out, and open /cms. Below the password form you should see Sign in with Microsoft.
  2. Click it, and sign in with an account in one of your mapped groups. You should land in the CMS.
  3. Under Settings › Users, that person shows a Microsoft badge next to their status, and the roles their group maps to.
  4. Optionally, move yourself from one group to the other in Entra, sign out of Cendia and sign in with Microsoft again: your role follows. Group changes can take a minute to reach Entra's sign-ins.

Other providers

Everything above applies to any OpenID Connect provider. What differs is where you find the three values and what the groups claim looks like.

Provider Authority Groups
Microsoft Entra https://login.microsoftonline.com/<tenant-id>/v2.0 Add a groups claim (step 4). Map groups by Object ID.
Okta https://<your-domain>.okta.com (or your custom authorization server's issuer) Add a groups claim to the ID token in the authorization server, with a filter for the groups you need. Map groups by name.
Auth0 https://<your-tenant>.auth0.com/ Auth0 has no groups claim of its own: add one with a post-login Action, under a namespaced name such as https://example.com/groups, and set GroupsClaim to that name.
Keycloak https://<host>/realms/<realm> Add a Group Membership mapper to the client, with token claim name groups and Add to ID token on. Turn off Full group path to map by plain name.
Google Workspace https://accounts.google.com Google doesn't send groups in its sign-in, so it can't be used with group mappings as they stand.

In every case, register https://<your-site>/cms/signin-oidc as the redirect URI, and ask for the openid, profile and email scopes (Cendia asks for these by default).

What people see

Situation What happens
First sign-in, no Cendia account An account is made with their address and name from the provider, and the groups their provider groups map to. It has no password.
First sign-in, a Cendia account already uses their address The account is linked and its password removed, unless it's the last password administrator (see below).
In no mapped group, or only in groups that don't map to Administrator or Author "You signed in, but your account is not in a group that may use this CMS."
The last administrator who signs in with a password "This address belongs to the CMS's only administrator who signs in with a password…" Create another administrator, then try again.
Locked out under Settings › Users "This account is locked."
Cancelled at the provider, or the provider refused "Signing in did not complete. Try again, or sign in with your password."

Signing out of the CMS signs the person out of Cendia only, not out of the provider. Clicking Sign in with Microsoft again usually signs them straight back in without asking.

Editing a linked person's roles

You can still change a linked person's roles under Settings › Users, and the change takes effect straight away. But their next sign-in sets them back to what their provider groups say, so the roles dialog warns you. To change someone's access for good, change their groups at the provider.

To stop someone signing in again straight away, without waiting for the provider, lock the account under Settings › Users. That holds whichever way they try to sign in.

Troubleshooting

What you see Why, and what to do
No Sign in with … button Cendia:Oidc:Enabled isn't true, or Authority or ClientId is empty, in this environment. Set them and restart.
Entra says the redirect URI doesn't match (AADSTS50011) The address in the error isn't one of the app's redirect URIs (step 1). Add it exactly, including http or https, the port and /cms/signin-oidc.
Entra says the client secret is invalid (AADSTS7000215) The secret is wrong, expired, or the Secret ID was copied instead of the Value. Create a new one (step 3) and update the setting.
"Signing in did not complete" every time The provider sent an error back. The server log has the provider's message. Common causes: the secret, or a redirect URI the provider doesn't know.
Everyone gets "not in a group that may use this CMS" The groups claim isn't being sent (step 4), or the mapping keys don't match what is sent: Entra sends Object IDs, not names. The server log says how many groups arrived for each refused sign-in.
One person who is in a lot of groups is refused Entra leaves the groups out of the sign-in for anyone in more than 200 of them. In Token configuration, edit the groups claim and choose Groups assigned to the application, then assign your Cendia groups to the app under Enterprise applications.
The server log says "GroupMappings names a group that does not exist" A mapping names a Cendia group nobody has created, or misspells one. Cendia never creates a group from a mapping. Create it under Settings › Groups, or fix the name.
"Your sign-in did not include an email address" The account has no email address or sign-in name at the provider. In Entra, give the user an email address, or make sure preferred_username is sent (it is, by default).

Configuration reference

Setting Default Meaning
Cendia:Oidc:Enabled false Turns single sign-on on.
Cendia:Oidc:DisplayName single sign-on What the button says after Sign in with, and the badge under Settings › Users.
Cendia:Oidc:Authority The provider's issuer address. Its settings are read from <Authority>/.well-known/openid-configuration.
Cendia:Oidc:ClientId The app's client ID. Not a secret.
Cendia:Oidc:ClientSecret The app's client secret. User-secrets or an environment variable only.
Cendia:Oidc:CallbackPath /cms/signin-oidc The redirect URI's path. Change it only if you also change it at the provider.
Cendia:Oidc:Scopes profile, email Scopes asked for besides openid.
Cendia:Oidc:GroupsClaim groups The claim that lists the person's groups.
Cendia:Oidc:EmailClaims email, preferred_username, upn The claims tried, in order, for the person's address.
Cendia:Oidc:GroupMappings (none) Provider group → the Cendia groups it grants. Matched without regard to case.

Cendia uses the authorization code flow with PKCE and doesn't keep the provider's tokens: once the person is signed in, nothing more is asked of the provider until their next sign-in.