This skill should be used when the user asks to "set up authentication", "add login", "add logout", "configure Entra ID", "set up Azure AD auth", "add Microsoft login", "enable authentication", "set up sign in", "add role-based access", "add authorization", "protect routes", "add auth to my site", "configure identity provider", or wants to set up authentication (login/logout via Microsoft Entra ID) and role-based authorization for their Power Pages code site.
Plugin check: Run
node "${PLUGIN_ROOT}/scripts/check-version.js"— if it outputs a message, show it to the user before proceeding.
Configure authentication (login/logout) and role-based authorization for a Power Pages code site. This skill supports multiple identity providers -- Microsoft Entra ID, Entra External ID (for customer-facing apps with self-service sign-up), OpenID Connect (Okta, Auth0, etc.), SAML2, WS-Federation, local authentication (username/password), Microsoft Account, Facebook, and Google. It also supports optional features including invitation-based registration and Terms & Conditions acceptance. Power Pages built-in 2FA is intentionally not scaffolded because the SendCode/VerifyCode pages are server-rendered and cannot be integrated into a SPA experience — use IdP-level MFA instead. It creates an auth service, type declarations, authorization utilities, auth UI components, and role-based access control patterns appropriate to the site's framework and chosen identity provider(s).
Initial request: $ARGUMENTS
Prerequisites:
- An existing Power Pages code site created via
/create-site- The site must be deployed at least once (
.powerpages-sitefolder must exist)- Web roles must be created via
/create-webroles
Goal: Confirm the project exists, identify the framework, verify deployment status and web roles, and check for existing auth code.
Look for powerpages.config.json in the current directory or immediate subdirectories:
**/powerpages.config.json
If not found: Tell the user to create a site first with /create-site.
Read package.json to determine the framework (React, Vue, Angular, or Astro). See ${PLUGIN_ROOT}/references/framework-conventions.md for the full framework detection mapping.
Look for the .powerpages-site folder:
**/.powerpages-site
If not found: Tell the user the site must be deployed first:
<!-- gate: setup-auth:1.3.deploy-first | category=plan | cancel-leaves=nothing -->"The
.powerpages-sitefolder was not found. The site needs to be deployed at least once before authentication can be configured."
🚦 Gate (plan · setup-auth:1.3.deploy-first):
.powerpages-sitemissing — auth setup writes site settings inside that folder. Deploy first or stop.Trigger: Phase 1.3 detected no
.powerpages-sitefolder. Why we ask: Auto-deploy picks the wrong env; skipping leaves auth wiring broken. Cancel leaves: Nothing — no auth files written yet.
Use AskUserQuestion:
| Question | Options | |----------|---------| | Your site needs to be deployed first. Would you like to deploy now? | Yes, deploy now (Recommended), No, I'll do it later |
If "Yes, deploy now": Invoke /deploy-site, then resume.
If "No": Stop — the site must be deployed first.
Look for web role YAML files in .powerpages-site/web-roles/:
**/.powerpages-site/web-roles/*.yml
Read each file and compile a list of existing web roles (name, id, flags).
<!-- gate: setup-auth:1.4.create-webroles | category=plan | cancel-leaves=nothing -->🚦 Gate (plan · setup-auth:1.4.create-webroles): No web roles found — role-based authorization needs at least one role. Create roles first or skip and add later.
Trigger: Phase 1.4 found no YAML files in
.powerpages-site/web-roles/. Why we ask: Auto-invoking/create-webrolesruns another full skill; auto-skipping leaves RBAC checks against an empty role set. Cancel leaves: Nothing — no auth files written yet.
If no web roles exist: Warn the user that web roles are needed for authorization. Ask via AskUserQuestion whether to create them first:
| Question | Options | |----------|---------| | No web roles were found. Web roles are required for role-based authorization. Would you like to create them now? | Yes, create web roles first (Recommended), Skip — I'll add roles later |
If "Yes": Invoke /create-webroles, then resume.
If "Skip": Continue — auth service and login/logout will still work, but role-based authorization will need roles created later.
Always run this discovery step, even on a first invocation — the site may have site settings from a prior run, or from hand-editing the YAML files, even if no SPA auth code exists yet. The goal is to make sure we never silently drop a provider that's already configured server-side.
Step 1 — Scan .powerpages-site/site-settings/ for already-configured providers.
Detect existing providers by matching site-setting filenames against these patterns:
| Pattern | Maps to provider type |
|---|---|
| Authentication-OpenIdConnect-{Name}-AuthenticationType.sitesetting.yml | OIDC (Entra External ID, Okta, Auth0, generic OIDC, B2C — all share the OIDC path) |
| Authentication-SAML2-{Name}-AuthenticationType.sitesetting.yml | SAML2 |
| Authentication-WsFederation-{Name}-AuthenticationType.sitesetting.yml | WS-Federation |
| Authentication-OpenAuth-{Microsoft\|Facebook\|Google}-{ClientId\|AppId}.sitesetting.yml | Social OAuth |
| Authentication-Registration-LocalLoginEnabled.sitesetting.yml with value true | Local Authentication |
For each detected provider, read its full set of .sitesetting.yml files to extract: Authority / MetadataAddress, ClientId / AppId, AuthenticationType (the providerIdentifier), Caption or display name (if present), and the {Name} slug used in the keys (e.g., OpenIdConnect_1, EntraExternalId).
Distinguishing Entra ID variants from OIDC — by Authority URL pattern:
| Authority pattern | Provider type | Notes |
|---|---|---|
| https://login.windows.net/{guid}/ (no /v2.0/) — site's parent tenant | Microsoft Entra ID (workforce) — type: 'entra-id' | Auto-populated by Power Pages on site creation. The {Name} slug is usually AzureAD. Set providerIdentifier to undefined in AUTH_PROVIDERS — runtime resolver derives it from Portal.tenant. |
| https://{subdomain}.ciamlogin.com/{tenantId} (no trailing /v2.0/) | Entra External ID — type: 'oidc' | Customer tenant. Must include explicit providerIdentifier matching the Authority. |
| https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/v2.0/{policy} | Azure AD B2C (legacy) — type: 'oidc' | Older B2C product. Must include explicit providerIdentifier. |
| Any other OIDC authority (Okta, Auth0, etc.) | OIDC — type: 'oidc' | Must include explicit providerIdentifier. |
The Entra ID (workforce) case is special — when Phase 1.5 discovery detects Authentication/OpenIdConnect/AzureAD/* settings on the site (which Power Pages auto-creates for the parent tenant), add a single entry to EXISTING_PROVIDERS:
{
id: 'entra-id',
type: 'entra-id',
displayName: existingCaption || 'Sign in with Microsoft',
// NO providerIdentifier — resolveProviderIdentifier() derives it from Portal.tenant
}
Do NOT extract the tenant ID from the existing Authority site setting just to hardcode it back into AUTH_PROVIDERS — the runtime resolver handles it. This keeps the SPA code portable if the site is ever cloned to a different tenant.
Step 2 — Scan for existing SPA auth code.
Check for these files and read their key markers:
src/services/authService.ts or .js — look for AUTH_PROVIDERS array (current pattern) vs single AUTH_PROVIDER constant (legacy)src/types/powerPages.d.ts — exists or notsrc/utils/authorization.ts — exists or notAuthButton.*, Login.*, Registration.*, RedeemInvitation.*, etc.) — list which existsrc/pages/Login.tsx — extract which providers it currently renders (via AUTH_PROVIDERS import or inline)Step 3 — Present findings to the user.
If providers were detected from site settings, present them with their config:
I found these existing auth providers on your site:
✓ Entra External ID
- ProviderName: OpenIdConnect_1
- Tenant: ba275000-98c8-404d-a6f0-c5450f2aa668
- ClientId: e728d63e-1190-495a-ae29-663e9cc10877
- Configured in site settings: yes
- Surfaced in SPA UI: NO (authService.ts has no entry for this provider)
✓ Local Authentication
- LoginByEmail: true
- Surfaced in SPA UI: yes
Use AskUserQuestion:
| Question | Header | Options | |----------|--------|---------| | I found existing auth providers on your site. What would you like to do? | Existing auth | Keep all existing providers and add a new one (Recommended) — preserves what's there, adds what you ask for next, Keep all existing providers (no new provider this run) — re-generates SPA code to surface what's already in site settings, Replace everything with a new configuration — wipes existing site settings and SPA code, starts fresh |
"Keep all existing providers and add a new one" (default path):
EXISTING_PROVIDERS — these will be merged into the AUTH_PROVIDERS array generated in Phase 3.2Local Authentication is in EXISTING_PROVIDERS, always regenerate the local auth SPA code (login flow, registration page, forgot/reset password, redeem invitation) from the user's Phase 2.1 answers. Don't try to preserve hand-edited local-auth code — the local flows are complex enough that partial updates introduce more bugs than they avoid."Keep all existing providers (no new provider this run)":
AUTH_PROVIDERS from EXISTING_PROVIDERS only"Replace everything with a new configuration":
EXISTING_PROVIDERS = []DO NOT offer a "skip / no changes" option. If the user invokes setup-auth, they want auth set up — silently doing nothing is worse than asking.
EXISTING_PROVIDERS list compiled from site settings, with provider type, ProviderName slug, ClientId/Authority/etc. for eachMERGE_MODE chosen: keep-and-add (default) | keep-only | replace-allAUTH_PROVIDERS array or legacy single-provider pattern)Goal: Gather authentication requirements from the user and present the implementation plan for approval.
Before asking the user which providers they want, analyze the site context from Phase 1 (site name, purpose, audience type) and try to infer appropriate auth settings automatically:
Inference rules:
| Site Type | Inferred Auth Settings | Rationale |
|-----------|----------------------|-----------|
| Internal/employee portal (HR, dashboard, admin) | Entra ID + invitation-only registration (OpenRegistrationEnabled=false, InvitationEnabled=true) | Internal sites should restrict access to invited employees only |
| Customer-facing portal (support, self-service) | Entra External ID + open registration | Customer portals need self-service sign-up for customers |
| Partner portal (B2B, vendor) | Entra ID + invitation-only registration | Partners are pre-vetted; open registration is a security risk |
| Public site with protected features (e-commerce, community) | Entra External ID + open registration + optional Google/Facebook | Public sites benefit from social login for frictionless sign-up |
| Loan/financial/banking portal | Entra External ID + invitation-only registration | Financial sites require controlled access for compliance |
If you can infer with confidence, present the recommendation with rationale:
"Based on your site purpose ({purpose}), I recommend:
- {provider} for authentication
- {registration mode} because {rationale}
Would you like to proceed with this configuration, or choose different providers?"
| Question | Options | |----------|---------| | Would you like to proceed with this recommended configuration? | Yes, proceed with recommendation, No, let me choose providers |
If "Yes": Skip Phase 2.1 provider selection and proceed directly to collecting provider-specific details (ClientId, tenant name, etc.) for the recommended provider(s).
If "No" or if you cannot infer with confidence: Fall back to Phase 2.1 below.
🚦 Gate (plan · setup-auth:2.1.requirements): Pick which auth features to build (login+logout / RBAC / both). Covers the conditional follow-up "which roles get access" sub-prompt in the same step.
Trigger: Phase 2.1 entry. Why we ask: Wrong feature set gets generated — e.g. building RBAC files when the user only wanted login. Cancel leaves: Nothing — no auth files written yet.
Re-run handling — when Phase 1.5 detected existing providers:
The behavior depends on the MERGE_MODE chosen in Phase 1.5:
keep-only (user chose "keep all existing, no new provider this run") → Skip the new-provider selection question entirely. Proceed to the "Local Authentication" follow-ups only if local was detected. Phase 3.2 will generate AUTH_PROVIDERS from EXISTING_PROVIDERS only.keep-and-add (default — user wants to add one more) → Ask the user what to add. The provider selection question below should still be multi-select (the user could be adding multiple new providers in one go), but the existing providers are NOT in the list (they're already configured — the question is asking what's new). Common patterns:
"You already have an Entra External ID provider configured for tenant {existing-tenant}. This new one is a separate instance — give it a distinct ProviderName slug (used in site setting keys like Authentication/OpenIdConnect/{ProviderName}/* and in code as the provider id)." Let the user pick a slug (default to the next incrementing number, e.g., OpenIdConnect_2) or pick a custom name (e.g., EntraExternalId_Employee).replace-all (user chose to wipe everything) → Run the provider selection question as on a first invocation.Do NOT proactively ask "do you want to configure multiple instances?" at the start. Walk the user through configuring ONE provider at a time. When they finish configuring one and want another, they can re-run setup-auth → Phase 1.5 detects what's there → Phase 2.1 in keep-and-add mode asks "what do you want to add now?". This keeps the question count low for the common case (configure one provider) while still supporting the advanced case (multiple tenants).
IMPORTANT: Multiple providers are supported. The user may want more than one identity provider (e.g., Entra External ID + Google). If the user's initial prompt mentions specific providers, skip the provider selection question and proceed directly to collecting details for each mentioned provider.
IMPORTANT — Local Authentication: NEVER set up local authentication by default. Do NOT include it in the provider selection list, do NOT recommend it in smart inference, and do NOT configure it unless the user explicitly and specifically asks for it (e.g., "I want username/password login", "set up local login", "add local auth"). External identity providers (Entra External ID, Entra ID, OIDC, etc.) are always preferred. If the user says something ambiguous like "add login", default to an external provider — never to local auth.
If the user has NOT specified which provider(s) they want, use AskUserQuestion to determine the identity provider(s). This is a multi-select question — the user can choose one or more:
| Question | Options | |----------|---------| | Which identity provider(s) do you want to use? (select all that apply) | Entra External ID (Recommended) — Customer identity with self-service sign-up (CIAM), Microsoft Entra ID — Azure AD / Entra ID for internal/employee sites, OpenID Connect — Okta, Auth0, or any OIDC-compliant provider, SAML2 — SAML 2.0 identity provider (ADFS, Shibboleth, Login.gov, etc.), WS-Federation — WS-Federation identity provider, Microsoft Account — Sign in with Microsoft personal/work account, Facebook — Sign in with Facebook, Google — Sign in with Google |
Then, for EACH selected provider, ask the mandatory follow-up questions below. Do not skip any provider — every selected provider needs its configuration collected before proceeding.
For each provider, also share the relevant Microsoft Learn documentation link so the user knows where to get the values:
For "Microsoft Account":
| Question | Options |
|----------|---------|
| What is the Client ID from your Microsoft app registration? (e.g., a1b2c3d4-e5f6-7890-abcd-ef1234567890) | (free text) |
Docs: https://learn.microsoft.com/en-us/power-pages/security/authentication/openid-settings
For "Facebook":
| Question | Options |
|----------|---------|
| What is the App ID from the Facebook Developer Console? (e.g., 1234567890123456) | (free text) |
Docs: https://learn.microsoft.com/en-us/power-pages/security/authentication/facebook-settings
For "Google":
| Question | Options |
|----------|---------|
| What is the Client ID from the Google Cloud Console? (e.g., 123456789-abc.apps.googleusercontent.com) | (free text) |
Docs: https://learn.microsoft.com/en-us/power-pages/security/authentication/oauth2-google
For "OpenID Connect" (Okta, Auth0, etc.):
First, identify the specific OIDC provider — setup steps and the docs to read differ per vendor:
| Question | Options | |----------|---------| | Which OpenID Connect provider are you using? | Okta, Auth0, Other (any OIDC-compliant provider) |
Use the answer as {provider} in the questions below and for Phase 2.1.2 Step A (reading the provider's docs). For Other, capture the provider's name from the user.
Orient the user first — don't jump straight to inputs. Now that they've picked {provider}, set expectations: you'll set up an app registration at {provider} for this site. The first thing you'll do is read {provider}'s own documentation — how it's set up depends on the provider. Then, depending on what {provider} supports, you'll either walk the user through the steps in the {provider} console, or — when {provider} supports it — configure it for the user. Either way you derive the metadata, Redirect URI, and claims automatically, and the app uses the no-secret code id_token flow — no client secret to manage.
Ask for the {provider} tenant — the sign-in domain (Okta: your-tenant.okta.com, Auth0: your-tenant.us.auth0.com):
| Question | Options |
|----------|---------|
| What's your {provider} tenant? | (free text) |
| What display name should the login button show? (default: Sign in) | (free text, defaulted) |
| Do you already have an app registration for this site at {provider}? | No — set one up in Phase 2.1.2 (Recommended), Yes — I already have one |
If the user answered "Yes — I already have one", ask for the existing Client ID and Metadata Address now (Phase 8.1 needs them) and skip the Phase 2.1.2 app-registration setup. Otherwise the Client ID is not asked upfront — it comes from Phase 2.1.2, where you set up the app (guided, or configured for the user when the provider supports it) and derive the metadata from the provider's discovery document.
Docs: https://learn.microsoft.com/en-us/power-pages/security/authentication/openid-settings
For "Entra External ID" — use the 4-step walkthrough below. Do NOT just ask the user for Authority/ClientId/Metadata upfront — those values come from a tenant + app registration + user flow that the user may not have set up yet. Walk them through each prerequisite before asking for the corresponding value.
Reference doc: https://learn.microsoft.com/en-us/power-pages/security/authentication/entra-external-id See also
${PLUGIN_ROOT}/skills/setup-auth/references/authentication-reference.mdfor the full Entra External ID prerequisites section the steps below cross-reference.
Pre-computed values for THIS site — before starting the walkthrough, compute:
SITE_URL = the deployed site URL (e.g., https://site-597pv.powerappsportals.com). Read from pac env who + the sSearch for places (restaurants, cafes, etc.) via Google Places API proxy on localhost.
Interact with GitHub using the `gh` CLI. Use `gh issue`, `gh pr`, `gh run`, and `gh api` for issues, PRs, CI runs, and advanced queries.
Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets.
Start voice calls via the OpenClaw voice-call plugin.
Notion API for creating and managing pages, databases, and blocks.
Gemini CLI for one-shot Q&A, summaries, and generation.
Category:developer