Authentication and Keycloak¶
Three hosts share the work:
sequenceDiagram
participant B as Browser
participant W as Web (BFF)
participant A as Auth server
participant K as Keycloak
participant API as API
B->>W: /bff/login
W->>A: OpenID Connect, PKCE
A-->>K: optional external login
K-->>A: verified email
A-->>W: code, tokens
W-->>B: session cookie
B->>W: /api/... with cookie
W->>API: bearer token
| Host | Package | Job |
|---|---|---|
| Auth | Coworkee.AuthServer |
OpenIddict server, sign-in, registration, password reset, two factor, account page, external providers |
| Web | Coworkee.Bff |
keeps tokens on the server, gives the browser a cookie, forwards /api, /odata, /hubs and /admin/jobs |
| API | Coworkee.AspNetCore |
validates bearer tokens (AddCoworkeeApiAuthentication) |
The browser never sees an access token. The sign-in with its tokens lives in a server-side session store (Redis when a redis connection string is set, otherwise memory), so the cookie only holds a session key. Requests from the client carry the X-CSRF: 1 header, which ApiClientBase adds.
Clients and scopes¶
The auth server creates its OpenID Connect clients from configuration on start. With the app host you set nothing; by hand it looks like this:
"Coworkee": {
"Auth": {
"ApiScopes": { "myapp_api": "myapp_api" },
"Clients": [{
"ClientId": "myapp-web",
"DisplayName": "MyApp",
"Scopes": [ "myapp_api" ],
"RedirectUris": [ "https://localhost:7300/signin-oidc" ],
"PostLogoutRedirectUris": [ "https://localhost:7300/signout-callback-oidc" ]
}]
}
}
Outside development, configure SigningCertificate and EncryptionCertificate (PKCS#12 path and password).
External login with Keycloak¶
Any OpenID Connect provider can sign users in. Each one is a section under Coworkee:Auth:External:Providers:
"Coworkee": {
"Auth": {
"External": {
"Mode": "Both",
"AutoProvision": true,
"Providers": {
"keycloak": {
"DisplayName": "Keycloak",
"Authority": "https://keycloak.example.com/realms/myapp",
"ClientId": "myapp-auth",
"ClientSecret": "..."
}
}
}
}
}
| Setting | Meaning |
|---|---|
Mode |
Internal password only, External providers only, Both (default) |
AutoProvision |
create a user on the first external sign-in when no account has the email |
Scopes |
defaults to openid profile email |
RequireHttpsMetadata |
false only for a local Keycloak on http |
On sign-in the auth server looks for the user in this order: the linked external login, then an account with the same email, then a new account. Linking by email requires the provider to mark the address as verified (email_verified) or to be configured with TrustEmail, otherwise the sign-in is refused. New users follow the registration settings and start without roles.
Locally, options.UseKeycloak() in the app host starts Keycloak with a realm for the app and configures all of this.

Setup wizard or seed¶
A new installation needs a tenant and a first administrator. Two ways:
Wizard. The API answers 503 setup_required until setup is done. The Blazor client shows the setup page: checks, organization, administrator, theme. The setup token is printed in the API log, or set with Coworkee:SetupToken. Sharemee works this way.
Seed. AddCoworkeeIdentitySeed in the migration service creates everything on the first start; the wizard never appears. The template works this way.
public static void Configure(IdentitySeedOptions seed)
{
seed.TenantName = "MyApp";
seed.Roles.Add(new SeedRole("Brand Manager", "Maintains brands", [CatalogPermissions.Brands.View, CatalogPermissions.Brands.Edit]));
seed.Users.Add(new SeedUser("admin@example.com", password, "Ada", "Admin", IsAdmin: true));
seed.Users.Add(new SeedUser("brands@example.com", password) { Roles = ["Brand Manager"] });
}
Account features¶
Registration is off by default; the setting Account.AllowRegistration turns it on, and apps from the template seed it on (--registration false leaves it off). The wizard, activation, allowed addresses, documents and the sign-in rules are described in Registration and sign-in rules; layout, theme and media of the account pages in Sign-in pages and designs. Users change password and two factor settings on the account page of the auth server, linked from the user menu. The email address changes under Account > Security in the app: after the current password, the new address gets a confirmation link and the old one a notice; the old address keeps working until the link is opened. An address another account uses gets no link, and the answer is the same, so nobody learns which addresses exist.
On a user's page administrators edit everything about the user: user name, names, phone, address, language, active, email confirmed, the address itself (at once, confirmed or with a confirmation mail; the old address gets a notice), the password (set one or send a reset link), an invitation for users without password, lockout, two-step verification reset, external sign-ins, roles, groups and the picture. New users are created in a dialog, either invited by mail to choose a password or with an initial password.
Administrators manage further clients and scopes in the app, end sessions at once and set password rules: see Clients, sessions and password rules.