> For the complete documentation index, see [llms.txt](https://islamu.gitbook.io/islamu-event/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://islamu.gitbook.io/islamu-event/documentation/readme/configuration-and-operations/authentication-providers.md).

# Authentication Providers

Configure Local Identity, Keycloak, or passwordless AT Protocol authentication.

ISLAMU Event supports three primary authentication authorities:

* **Local Identity** - embedded ASP.NET Core Identity with platform-issued JWTs.
* **Keycloak** - an external OpenID Connect authority.
* **AT Protocol** - passwordless sign-in authorized against each user's personal data server.

Exactly one provider is primary for new sign-ins. AT Protocol can also remain an optional login method while Local Identity or Keycloak is primary.

Setup keeps the selected provider's ready, action-required, unavailable, failed and restart-required states visible. Opening advanced configuration does not change authority or silently fall back to Local. After completion, use the provider-management action offered by the getting-started checklist; ordinary sign-in replaces setup authority for status and journey reads.

## Recommended Choice for Self-Hosters

1. **Local Identity is the recommended default**, especially for Docker Standalone. It is embedded, works on localhost and private networks, and needs no separate identity service. This is why the standalone image defaults to Local Identity.
2. **AT Protocol is the second-best choice for the average self-hoster** who has a public HTTPS domain. Users authorize with their AT Protocol account (commonly their Bluesky handle), so the host does not collect or manage their passwords. It is not the first default because decentralized OAuth callbacks require a publicly reachable HTTPS origin and therefore do not work on localhost-only installations.
3. **Keycloak is recommended for serious hosting teams and SaaS operators**. It carries the highest operational cost, but offers the most advanced centralized identity lifecycle, SSO/federation, multi-factor/2FA options, policies, and enterprise administration.

You can start with Local Identity and deliberately switch later after linking the administrator to the target provider. The server prevents a switch that would remove every usable administrator sign-in path.

## Supported Provider States

| Primary provider | AT Protocol login | Result                          |
| ---------------- | ----------------: | ------------------------------- |
| `local`          |           `false` | Local Identity only             |
| `local`          |            `true` | Local Identity plus AT Protocol |
| `keycloak`       |           `false` | Keycloak only                   |
| `keycloak`       |            `true` | Keycloak plus AT Protocol       |
| `atproto`        |            `true` | AT Protocol only                |

`AUTHENTICATION_PROVIDER=atproto` requires `ATPROTO_LOGIN_ENABLED=true`. The application rejects the contradictory `false` combination. Google SSO is disabled in AT Protocol-only mode.

## Development-only agent browser profile

Contributors who need predictable real-browser Local Identity sessions can use the opt-in Aspire `local-agent` launch profile. It is strictly Development-only, Split-only, and isolated from ordinary Aspire data. It starts PostgreSQL, Redis, Mailpit, the migration service, API, and BFF; it does not start Keycloak, Cerbos, RabbitMQ, MinIO, or the larger local platform stack. This is reduced infrastructure, not a zero-container or startup-latency guarantee.

Before launch, choose one existing secret authority and supply the Local JWT signing key, configured-administrator bootstrap password, and agent persona password under `AUTHENTICATION_LOCAL_JWT_KEY`, `INSTANCE_BOOTSTRAP_LOCAL_PASSWORD`, `AGENT_BROWSER_PERSONA_PASSWORD`, `POSTGRESQL_USERNAME`, `POSTGRESQL_PASSWORD`, and `AGENT_BROWSER_REDIS_PASSWORD`. Do not put their values in source, launch settings, shell history, screenshots, or browser automation output. The profile honors Environment, Development User Secrets, or Infisical exactly as selected and does not fall back to another provider. Persona, bootstrap, and Local JWT values are forwarded only to the API; the BFF and migration service do not receive them. Select the provider in the launching shell or the ignored repository `.env` before running the profile; a new terminal does not inherit the previous selection. An incomplete authority fails closed rather than resetting the isolated data or switching providers.

```bash
dotnet build --configuration Release --verbosity quiet
# Select SECRET_PROVIDER in this shell or the ignored repository .env first.
dotnet run --project src/Explore.AppHost/Explore.AppHost.csproj \
  --configuration Release --no-build --launch-profile local-agent
```

Use `http://localhost:5200` for discovery, `http://default.localhost:5200` for the fixture tenant, and `http://admin.localhost:5200` for instance administration. The API is fixed at `http://localhost:5100`; Mailpit is at `http://localhost:58025` with SMTP on `localhost:51025`. A port conflict or unsafe topology fails startup instead of silently changing the origin or using a populated ordinary-development store. Wait for migration, API, and BFF readiness rather than using a fixed delay. The dedicated PostgreSQL, Redis, and Mailpit containers use a 2048-process limit for consistent Docker and Podman startup; this is not a startup-time guarantee. Geocoding is disabled for this profile.

On first provisioning, the isolated instance enables tenant subdomains under `localhost` and binds `default` and `agent-negative` to the corresponding synthetic tenants. Later changes to its routing settings are preserved on restart.

The profile provisions synthetic `@agent.example.test` identities only through the native Local credential lifecycle. Sign in through the visible `/login` form on the selected tenant or admin host; a successful response is not an authenticated browser session until `/auth/status` reports the intended identity after navigation. Local credential verification, the authenticated current-user check, and the admin-authority check work on the admin host without a tenant; ordinary tenant-scoped API requests still require a resolved tenant. Do not inject cookies or bearer tokens. Passwords, revoked grants, and profile changes are not reset on a completed restart. PostgreSQL, Redis, Mailpit, local object storage, and privacy-erasure data use dedicated agent-profile locations; stopping Aspire preserves them. Never delete those volumes or directories as a routine retry. Diagnose the bounded startup failure first, and obtain explicit approval before destructive reset.

## Keycloak Account Claims

Keycloak must issue the same authoritative account `sub` in the ID token and API access token, with its configured issuer. A successful browser callback alone is not enough if the API access token has no subject. Session IDs and platform user IDs are not substitutes.

The supplied realm exports include Keycloak's built-in **Subject** mapper (`oidc-sub-mapper`) on the `islamu-event-blazor` client, with inclusion enabled for access tokens, ID tokens and introspection. Automatic Keycloak setup also checks and repairs this mapper. For an already imported realm, use the realm doctor's Subject mapper check and additive realm sync (after confirming your backup), or enable the native Subject mapper directly in Keycloak. Then sign out and sign in again to obtain new tokens; restarting Event or replacing the export file alone does not repair an existing realm or change issued tokens. Keep the existing API audience mapper and email-verification mapping. Do not add a hard-coded subject or mark an email verified to work around sign-in failures.

## Safe Keycloak Connection And Inspection

A correctly configured deployment connects with its existing runtime BFF credential. The application resolves the Keycloak endpoint, realm, client ID and client secret from the deployment's selected secret authority; it does not copy the secret into the application database or ask an administrator to re-enter it. If that authority is unavailable or unauthorized, repair the selected authority and restart the affected replicas rather than adding a fallback value.

Basic discovery is read-only and needs no Keycloak administrator account. Advanced inspection is a separate request and requires credentials entered freshly in that form. Those credentials are used only for the foreground request and are not read from deployment configuration, retained as a session, or written to logs and support artifacts.

For an existing realm, Event does not change realm settings, users, roles, shared client scopes, sessions, existing-client flow/type settings, or client secrets. It recognizes effective native and inherited subject/audience mappings without creating duplicates. Ordinary browser refresh does not require `offline_access`; missing offline-token policy is not treated as a launch failure. Unsupported prerequisites are shown as manual Keycloak steps.

### Create-only provisioning and credential rotation

Event can create a realm or client only when an advanced inspection proves the resource absent. You must explicitly choose **Create realm**, **Create clients** or **Repair client** and review the generated receipt before Apply. Existing realms and clients are never adopted, replaced or synchronized. Realm/client name races stop with a conflict, and an interrupted create remains **outcome unknown** until read-only reconciliation verifies the captured provider ID.

For a new confidential BFF client, Event reads the runtime secret from the selected deployment authority and sends it directly to Keycloak for that one-time create. The API client is bearer-only and receives no secret. The browser never submits or receives the runtime client secret.

Rotate an existing BFF client secret outside Event:

1. Update Keycloak and the selected Infisical/environment secret together.
2. Restart every affected API and BFF replica.
3. Run connection and advanced inspection again.
4. Complete a fresh user sign-in.

Event does not rotate, persist, copy, retry or roll back provider credentials. The retired bootstrap, realm-sync and client-secret rotation routes have no compatibility aliases.

Event never creates Keycloak users, passwords, MFA enrollment or realm roles. After provisioning an absent realm/client, create the first identity in Keycloak through the provider's native administration flow, then complete the Event setup flow to bind the platform administrator.

Starting or restarting Event never reconciles an existing Keycloak realm. A new managed-local Keycloak database starts without the sample realm; provision absent resources through the same explicit inspection and receipt workflow. Do not delete or reimport an existing realm to apply Event configuration.

### Approved operations and interrupted requests

Before Event sends an approved Keycloak change, it stores a credential-free operation receipt. The receipt binds the exact instance, authority, realm, client targets, reviewed change digest and either the verified administrator who created it or the server-derived setup generation. It expires after 15 minutes; a changed target, approval, setup generation, or administrator cannot reuse it.

The operator API has seven private, no-store routes under `/api/instance/keycloak`: connection, inspect, plans, receipt read, apply, reconcile, and cancel. Each request requires current setup or instance administrator authority. Inspect and apply prompt for administrator credentials only in the advanced form for that request. They are never saved in a browser session or receipt, and the receipt contains no credentials, tokens, or provider response body. These routes do not use generic idempotency response replay.

The same operator panel appears during setup and in instance authentication settings. Buttons are shown only when the server includes the matching HAL affordance. Applying requires reviewing the receipt and typing the explicit confirmation phrase; credentials and confirmation are cleared after every attempt.

If the response is lost, Event reports **outcome unknown** and blocks another operation for that realm. Do not click Apply again or repeat the change manually. Run read-only reconciliation first. Cancellation can prevent work that has not been sent; after transmission it records your request but cannot undo Keycloak. Event never automatically retries or rolls back a provider write.

Back up the application database together with Keycloak before an approved change. Settled receipts are retained for at least 30 days. Unresolved receipts are retained until reconciliation and are never replayed automatically.

## Passwordless AT Protocol Onboarding

1. Start first-run setup and choose **AT Protocol** as the primary provider.
2. Configure the public instance URL used by AT Protocol OAuth metadata.
3. Save the provider configuration.
4. Enter the administrator's AT Protocol handle on the focused sign-in page.
5. Authorize the request at the account's personal data server.
6. Return to the setup wizard and complete instance onboarding.

No local password, Local Identity account, or Keycloak realm is created. The OAuth return creates one passwordless platform account for the verified DID. Administrator authority is granted only while the original setup-secret session completes onboarding; OAuth success by itself cannot claim the instance.

The instance still needs its server-only AT Protocol confidential-client ES256 key ring. Store that key ring through the selected secret authority. It signs OAuth client assertions; it is not a user password and is never sent to the browser.

## Runtime Behavior

The browser receives an encrypted HttpOnly BFF cookie. Provider access tokens, OAuth session material, and platform bearer tokens remain server-side.

In AT Protocol-only mode:

* `/auth/providers` advertises only the ready AT Protocol handle flow;
* the login page opens the handle field immediately;
* Local Identity login and registration fail closed;
* unlinked verified DIDs are provisioned without a local password;
* repeated or concurrent first login converges on one account.

Existing sessions continue under the provider that issued them until normal expiry. Changing the primary provider controls new sign-in admission; it does not reinterpret an existing cookie as a different authority.

## Email Verification Is Explicit

A successful provider sign-in does not by itself verify an email address. ISLAMU Event records provider verification only when the authenticated identity explicitly supplies `email_verified=true`. Missing, malformed, and false claims remain unverified, including for Keycloak and Google. Configure the provider's claim mapping if applications need its verified-mailbox evidence; do not replace missing evidence with a blanket verified default.

AT Protocol identities without an email address remain valid passwordless identities. Event's outbound-email setting does not change provider verification or take over the provider's recovery workflow.

## Switching Providers Safely

Use **Administration -> Instance Settings -> Authentication and Authorization Providers**. The selector offers Local Identity, Keycloak, and AT Protocol.

Before switching:

* confirm the current administrator already has an exact account binding for the target provider;
* keep the target provider healthy and reachable;
* do not disable the only provider linked to the current administrator;
* keep AT Protocol enabled while it is primary.

The server performs the authoritative self-lockout check. The confirmation dialog is guidance, not authorization.

## Break-Glass Recovery

If every interactive administrator path is lost but the target DID is already linked, follow [Lost Instance Administrator Access](/islamu-event/documentation/readme/configuration-and-operations/troubleshooting-and-health.md#recipe-7-lost-instance-administrator-access). The recovery tool does not create accounts, resolve handles, change onboarding state, or grant tenant authority.

## Related

* [Environment Variables](/islamu-event/documentation/readme/configuration-and-operations/environment-variables.md)
* [Troubleshooting & Operational Health](/islamu-event/documentation/readme/configuration-and-operations/troubleshooting-and-health.md)
* [First-Run Administration](/islamu-event/documentation/readme/administration-and-branding/admin-guide.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://islamu.gitbook.io/islamu-event/documentation/readme/configuration-and-operations/authentication-providers.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
