Skip to main content

Azure AD as OIDC provider

This how-to describes how to configure Azure AD as an OIDC provider for a tenant in an Avassa system. In the how-to we create a new tenant, an OIDC provider can of course be added to an existing tenant as well.

Prepare Azure AD

We need to prepare our Control Tower as an OIDC client in Azure AD. All this configuration is done in the Azure Active Directory config in Azure.

App Registration

app-registration

Click New registration

new-registration

note

Make sure you add a redirect URI here, the path is: <env-name>.<org-name>.avassa.net/oidc-callback

After saving, you will see something like this, make a note of the Application (client) ID

client-id

Client Secret

Next create a new secret by clicking Client credentialsand add a client secret.

client-secret

Note the Value of the secret.

warning

The client secret has an expiry date, so you will have to refresh this.

You will see this in the system:logs topic:

<ERROR>   2025-10-02 07:17:31.434675Z control-tower/ip-10-20-20-1: Failed to grant oidc token: Message from OIDC server (401) {"error":"invalid_client","error_description":"AADSTS7000222: The provided client secret keys for app '...' are expired. Visit the Azure portal to create new keys for your app: https://aka.ms/NewClientSecret, or consider using certificate credentials for added security: https://aka.ms/certCreds.

Endpoint URL

Next client Endpoints here:

endpoints

And note OpenID Connect metadata document

metadata

Add email claim

To make sure the email address is available in the Avassa system, we need to add the email claim. Click Token configuration and then Add optional claim.

Select Token type: ID and then select email and click Add. email-claim

Add user groups claim

For this tutorial, we will map Azure AD groups to policies in the Avassa System. To add groups as a claim, select the app registration and add groups claim:

claim

Group overage (more than ~200 groups)

Azure AD includes group memberships directly in the token's groups claim. However, if a user is a member of more than approximately 150-200 groups, Azure AD triggers group overage - the groups claim is omitted and replaced with an indicator that groups must be fetched separately via Microsoft Graph.

Avassa handles this automatically. The User.Read delegated permission (which most app registrations already have) is sufficient, since Avassa calls /me/getMemberGroups on behalf of the signed-in user.

  1. Go to API permissions and verify that User.Read (Microsoft Graph, Delegated) is listed and has consent granted. This is added by default for new app registrations.
  2. If it is missing: click + Add a permission > Microsoft Graph > Delegated permissions, search for User.Read, click Add permissions, and grant consent.

Then make sure oidc-scopes on the OIDC role includes at least profile and email (see role configuration below). These are Graph-level scopes that cause Entra to issue the access token for Microsoft Graph.

When this is configured, Avassa will detect that the access token is a Microsoft Graph token and use it directly to call /me/getMemberGroups to retrieve the user's group memberships. The flow looks like this:

User signs in via Entra
|
v
Avassa receives id_token + access_token
- id_token: aud = <client-id>, contains overage indicators
- access_token: aud = Microsoft Graph (issued because oidc-scopes
includes profile/email which are Graph scopes)
|
| POST /v1.0/me/getMemberGroups (with access_token)
v
Microsoft Graph returns the user's security group memberships
|
v
Avassa uses the groups for role matching

When oidc-scopes includes Graph-level scopes like profile and email, Entra issues the access token directly for Microsoft Graph (audience 00000003-0000-0000-c000-000000000000). Avassa detects this and uses the token as-is, without needing an OBO (On-Behalf-Of) exchange. The User.Read permission (with consent) allows the token to call /me/getMemberGroups.

note

If all your users have fewer than ~150 groups, no extra configuration is needed - the groups claim will be included directly in the token.

tip

To reduce the number of groups in the token, you can set "groupMembershipClaims": "SecurityGroup" in the app manifest. This excludes distribution lists and Microsoft 365 groups, which may bring the count below the overage threshold.

Alternatives if group overage is still a problem:

  • Limit groups per user - set "groupMembershipClaims": "SecurityGroup" in the app manifest to exclude distribution lists and Microsoft 365 groups. If the user has fewer than ~150 security groups, the groups claim fits in the token directly.
  • Allow sign-in without groups (lenient) - Avassa signs the user in but without group memberships. Role matching based on groups will not work. This is Avassa's default behaviour when group fetching fails - no explicit configuration is required.

Azure AD Information

You should now have the following values from Azure:

client IDdd3ef79f-b9b4-44bd-b1ec-e71b221e0e96
client secretLCq8Q~lls7H4AYpD-J2~dI1BjumZbbET8GXincAx
Discovery URLhttps://login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/v2.0/.well-known/openid-configuration

Configure OIDC for a tenant

First we will create a new tenant, in this example we will call this tenant popcorn-inc.

supctl replace tenants popcorn-inc <<EOF
name: popcorn-inc
kind: application-owner
policies:
- app-owner-tenant
EOF

Next we will generate a root token for this tenant.

warning

Make sure you take note of the token below, it will be used in subsequent supctl calls below. You can only call create-root once.

supctl do strongbox token create-root --name popcorn-inc
Warning: Providing --name on the command line is insecure. Consider using --name-prompt instead.
{
"accessor": "c51e2c8d-1cab-4d36-9880-294bc5529059",
"token": "6c1fa04e-463a-4e61-bcc9-fd1e072f16cc",
"creation-time": "2023-01-16T11:36:10.549630Z"
}

With the discovery URL, client ID and the secret from above, we can now create the oidc service.

NOTE 1: make sure allowed-redirect-uris match what you configured in Azure above.

NOTE 2: role-claim: groups will try to match all group names in the groups to oidc roles.

note
  • 6c1fa04e-.. is the token generated above
supctl -t 6c1fa04e-463a-4e61-bcc9-fd1e072f16cc replace strongbox authentication oidc-services azure-ad <<EOF
name: azure-ad
display-name: azure-ad
# Replace me
discovery-url: https://login.microsoftonline.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/v2.0/.well-known/openid-configuration
use-root-ca-certs: true
# Replace me
client-id: dd3ef79f-b9b4-44bd-b1ec-e71b221e0e96
# Replace me
client-secret: LCq8Q~lls7H4AYpD-J2~dI1BjumZbbET8GXincAx
verbose-logging: true
role-select:
role-claim: groups
allowed-redirect-uris:
# Replace me
- https://my-env.example.avassa.dev/oidc-callback
EOF
tip

verbose-logging: true can be helpful while setting up and testing. See troubleshooting for helpful logs.

note

Verbose logging should be disabled in production:

supctl -t 6c1fa04e-463a-4e61-bcc9-fd1e072f16cc merge strongbox authentication oidc-services azure-ad <<EOF
verbose-logging: false
EOF

Now we will create OIDC roles to match an Azure groups. Azure groups are sent in the form of guids, you can find the roles in azure in the Groups menu, there the group names and guid (Object Id) are listed.

note
  • dbb4bd8f-.. is the Object Id for the Azure group.
  • 6c1fa04e-.. is the token generated above

Here we match the dbb4bd8f-c8a9-45c1-a6d2-5456f2fcb6b9 group id to a root and user policy.

supctl -t 6c1fa04e-463a-4e61-bcc9-fd1e072f16cc create strongbox authentication oidc-services azure-ad roles <<EOF
name: dbb4bd8f-c8a9-45c1-a6d2-5456f2fcb6b9

# If the email claim is not present, deny access
required-claims:
- email
# Map email claim to username in the Avassa system
claim-mappings:
email: username
name: fullname

oidc-scopes:
- profile
- email

# Map this group to the following policies
token-policies:
- root
- user
EOF

Claim mappings

In the above example we map email from Azure AD to username in the Avassa system. This will ensure the email address is logged in the audit trail logs and rendered in the UI.

The fullname mapping is optional, it will be used to render the user's name in the UI.

Test Login

To login, go to your environment and click change tenant change-tenant

Click get login options and then login with azure-ad. login

At this point you will be redirected to Azure and after logging in, redirected back into Control Tower.

Troubleshooting

In case login fails, you can find useful information in the following topics:

  • system:logs
  • system:audit-trail-log
supctl -t 6c1fa04e-463a-4e61-bcc9-fd1e072f16cc do volga topics system:logs consume --payload-only

Common issues

SymptomLikely causeAction
OIDC role-select claim missing: groupsUser has >200 groups (overage) and Graph group fetch is not workingFollow the group overage steps above
AADSTS65001Admin consent missing for a required permissionGrant admin consent in Azure Portal > API permissions
AADSTS50013 in OBO flowAccess token is already a Graph token; OBO is not applicableEnsure oidc-scopes includes profile and email (not api://.../access_as_user)
AADSTS7000222Client secret has expiredCreate a new secret in Azure Portal > Certificates & secrets
Graph group fetch failed / Graph returns 403User.Read permission missing or not consentedVerify that User.Read is listed under API permissions with consent granted