Entra OIDC App Integration
Use this skill for Microsoft Entra app registration and OIDC SSO work, especially
when an app needs an Entra login button, group-based RBAC, a client secret, or a
safe cutover from local admin to SSO.
Routing
- Use Azure MCP/plugin best-practices for Entra/Azure operations before changing
Azure/Entra resources.
- Use
infisical-secrets-management before reading, writing, rotating, staging,
or injecting any client secret value.
- Use repo-native runbooks/source when they exist. Do not invent a parallel
authority path for GitOps-managed config.
Safety Boundary
- Treat app IDs, tenant IDs, issuer URLs, redirect URIs, and group object IDs as
non-secret but still avoid overexposing them in public docs.
- Treat client secrets, secret IDs when operationally sensitive, refresh tokens,
OAuth state, cookies, kubeconfigs, and service tokens as secret-value material.
- Do not print, commit, screenshot, paste, or log secret values.
- If a value must be materialized locally, use
mktemp, umask 077, no shell
tracing, and delete it with trap.
- Keep local/break-glass admin enabled until SSO login and admin access are
proven in the browser.
- Disable local admin only as a separate approved change.
Entra App Checklist
For a typical confidential web app:
signInAudience=AzureADMyOrg unless multi-tenant access is explicitly needed.
- Redirect URI exactly matches the app callback, for example
https://<host>/auth/callback.
- ID token issuance enabled when the app needs OIDC login.
- Access token implicit grant disabled unless the app explicitly requires it.
groupMembershipClaims=SecurityGroup when RBAC depends on Entra security
group claims.
- Operator account is in the intended admin group before cutover.
- Client secret is rotated/staged through the approved secret manager, not typed
into config files.
Metadata-only checks:
az ad app show \
--id <client-id> \
--query '{displayName:displayName,appId:appId,signInAudience:signInAudience,groupMembershipClaims:groupMembershipClaims,redirectUris:web.redirectUris,implicitGrant:web.implicitGrantSettings}' \
-o json
az ad group member check \
--group <admin-group-object-id> \
--member-id <operator-user-object-id> \
-o json
Scopes And Group Claims
Do not request groups as an OAuth scope for Microsoft Entra unless the target
resource explicitly exposes such a scope. For normal Entra OIDC app login:
- Requested scopes are usually
openid, profile, and email.
- Group membership is emitted as a token claim because the app registration has
groupMembershipClaims=SecurityGroup.
- The consuming app may still need a local setting telling it to read the
groups claim. For Argo CD this is argocd-rbac-cm scopes: '[groups]'.
If Entra returns AADSTS650053 for scope groups, remove groups from
requested OAuth scopes and keep group-claim/RBAC handling in the app config.
Client Secret Handling Pattern
Generate and stage the secret value without printing it:
SECRET_FILE="$(mktemp)"
trap 'rm -f "$SECRET_FILE"' EXIT
umask 077
az ad app credential reset \
--id <client-id> \
--append \
--display-name "<rotation-label>" \
--years 1 \
--query password -o tsv | tr -d '\r\n' > "$SECRET_FILE"
# Store through the approved secret manager. Example only; use repo-local path.
infisical secrets set "<SECRET_NAME>=@${SECRET_FILE}" \
--env <env> \
--path <path> \
--projectId <project-id> \
--silent >/dev/null
Important:
- Use the client secret value, not the secret ID.
- Strip trailing newlines before injecting into consumers.
- Prefer
--from-literal for Kubernetes secret keys when the source value is a
single credential string.
Argo CD Specifics
When Argo CD uses clientSecret: $<secret-name>:<key>:
- The Kubernetes secret must be in the
argocd namespace.
- It must have label
app.kubernetes.io/part-of=argocd.
- The referenced key must exist, for example
clientSecret.
- Restart or roll
argocd-server after changing OIDC config or secret value.
Shape-only verification:
kubectl -n argocd get secret <secret-name> -o json |
jq -r '{name:.metadata.name,labels:.metadata.labels,has_clientSecret:(.data|has("clientSecret")),clientSecret_b64_len:(.data.clientSecret|length)}'
If Entra returns AADSTS7000215, check:
- secret value vs secret ID
- trailing newline in the stored value
- missing Argo label on the Kubernetes secret
- app registration/client ID mismatch
- old
argocd-server pod still holding stale config
Public Repo Hygiene
In public repos:
- Keep deployment-required non-secret identifiers in source only where needed.
- Prefer placeholders in prose runbooks for tenant IDs, client IDs, group object
IDs, secret-manager paths, and human account object IDs.
- Never include secret values, secret IDs, OAuth state, screenshots with tokens,
raw curl/browser callback dumps, private Infisical paths, or user object IDs in
committed docs unless there is an explicit public-disclosure reason.
Verification Closeout
Before calling the work done:
- App registration metadata matches expected redirect URI and group claim mode.
- Secret exists in the approved secret manager and live consumer, without value
disclosure.
- App config requests valid OAuth scopes only.
- RBAC maps the exact intended group claim.
- Local/break-glass admin remains enabled until browser SSO is proven.
- Browser login succeeds and admin access is confirmed.
- Source, live state, and runbook agree.
- Follow-up to disable local admin is separate and reversible.
Workflow Coordination
This skill owns Entra OIDC integration, app-registration checks, and SSO proof.
Use infisical-secrets-management for secret inventory, staging, injection,
rotation, and redacted proof. Use browser-form-privacy-flow for browser login
or admin-console actions with sensitive fields.
1---2name: entra-oidc-app-integration3description: Microsoft Entra OIDC app integrations with Argo CD, Grafana, Kubernetes dashboards, or CI/CD tools: app registrations, redirect URIs, client secrets, group claims, RBAC group mapping, and SSO cutover verification. Not for general Microsoft 365 tenant administration (m365-admin).4---56# Entra OIDC App Integration78Use this skill for Microsoft Entra app registration and OIDC SSO work, especially9when an app needs an Entra login button, group-based RBAC, a client secret, or a10safe cutover from local admin to SSO.1112## Routing1314- Use Azure MCP/plugin best-practices for Entra/Azure operations before changing15 Azure/Entra resources.16- Use `infisical-secrets-management` before reading, writing, rotating, staging,17 or injecting any client secret value.18- Use repo-native runbooks/source when they exist. Do not invent a parallel19 authority path for GitOps-managed config.2021## Safety Boundary2223- Treat app IDs, tenant IDs, issuer URLs, redirect URIs, and group object IDs as24 non-secret but still avoid overexposing them in public docs.25- Treat client secrets, secret IDs when operationally sensitive, refresh tokens,26 OAuth state, cookies, kubeconfigs, and service tokens as secret-value material.27- Do not print, commit, screenshot, paste, or log secret values.28- If a value must be materialized locally, use `mktemp`, `umask 077`, no shell29 tracing, and delete it with `trap`.30- Keep local/break-glass admin enabled until SSO login and admin access are31 proven in the browser.32- Disable local admin only as a separate approved change.3334## Entra App Checklist3536For a typical confidential web app:3738- `signInAudience=AzureADMyOrg` unless multi-tenant access is explicitly needed.39- Redirect URI exactly matches the app callback, for example40 `https://<host>/auth/callback`.41- ID token issuance enabled when the app needs OIDC login.42- Access token implicit grant disabled unless the app explicitly requires it.43- `groupMembershipClaims=SecurityGroup` when RBAC depends on Entra security44 group claims.45- Operator account is in the intended admin group before cutover.46- Client secret is rotated/staged through the approved secret manager, not typed47 into config files.4849Metadata-only checks:5051```bash52az ad app show \53 --id <client-id> \54 --query '{displayName:displayName,appId:appId,signInAudience:signInAudience,groupMembershipClaims:groupMembershipClaims,redirectUris:web.redirectUris,implicitGrant:web.implicitGrantSettings}' \55 -o json5657az ad group member check \58 --group <admin-group-object-id> \59 --member-id <operator-user-object-id> \60 -o json61```6263## Scopes And Group Claims6465Do not request `groups` as an OAuth scope for Microsoft Entra unless the target66resource explicitly exposes such a scope. For normal Entra OIDC app login:6768- Requested scopes are usually `openid`, `profile`, and `email`.69- Group membership is emitted as a token claim because the app registration has70 `groupMembershipClaims=SecurityGroup`.71- The consuming app may still need a local setting telling it to read the72 `groups` claim. For Argo CD this is `argocd-rbac-cm` `scopes: '[groups]'`.7374If Entra returns `AADSTS650053` for scope `groups`, remove `groups` from75requested OAuth scopes and keep group-claim/RBAC handling in the app config.7677## Client Secret Handling Pattern7879Generate and stage the secret value without printing it:8081```bash82SECRET_FILE="$(mktemp)"83trap 'rm -f "$SECRET_FILE"' EXIT84umask 0778586az ad app credential reset \87 --id <client-id> \88 --append \89 --display-name "<rotation-label>" \90 --years 1 \91 --query password -o tsv | tr -d '\r\n' > "$SECRET_FILE"9293# Store through the approved secret manager. Example only; use repo-local path.94infisical secrets set "<SECRET_NAME>=@${SECRET_FILE}" \95 --env <env> \96 --path <path> \97 --projectId <project-id> \98 --silent >/dev/null99```100101Important:102103- Use the client secret value, not the secret ID.104- Strip trailing newlines before injecting into consumers.105- Prefer `--from-literal` for Kubernetes secret keys when the source value is a106 single credential string.107108## Argo CD Specifics109110When Argo CD uses `clientSecret: $<secret-name>:<key>`:111112- The Kubernetes secret must be in the `argocd` namespace.113- It must have label `app.kubernetes.io/part-of=argocd`.114- The referenced key must exist, for example `clientSecret`.115- Restart or roll `argocd-server` after changing OIDC config or secret value.116117Shape-only verification:118119```bash120kubectl -n argocd get secret <secret-name> -o json |121 jq -r '{name:.metadata.name,labels:.metadata.labels,has_clientSecret:(.data|has("clientSecret")),clientSecret_b64_len:(.data.clientSecret|length)}'122```123124If Entra returns `AADSTS7000215`, check:125126- secret value vs secret ID127- trailing newline in the stored value128- missing Argo label on the Kubernetes secret129- app registration/client ID mismatch130- old `argocd-server` pod still holding stale config131132## Public Repo Hygiene133134In public repos:135136- Keep deployment-required non-secret identifiers in source only where needed.137- Prefer placeholders in prose runbooks for tenant IDs, client IDs, group object138 IDs, secret-manager paths, and human account object IDs.139- Never include secret values, secret IDs, OAuth state, screenshots with tokens,140 raw curl/browser callback dumps, private Infisical paths, or user object IDs in141 committed docs unless there is an explicit public-disclosure reason.142143## Verification Closeout144145Before calling the work done:146147- App registration metadata matches expected redirect URI and group claim mode.148- Secret exists in the approved secret manager and live consumer, without value149 disclosure.150- App config requests valid OAuth scopes only.151- RBAC maps the exact intended group claim.152- Local/break-glass admin remains enabled until browser SSO is proven.153- Browser login succeeds and admin access is confirmed.154- Source, live state, and runbook agree.155- Follow-up to disable local admin is separate and reversible.156157## Workflow Coordination158159This skill owns Entra OIDC integration, app-registration checks, and SSO proof.160Use `infisical-secrets-management` for secret inventory, staging, injection,161rotation, and redacted proof. Use `browser-form-privacy-flow` for browser login162or admin-console actions with sensitive fields.