WebUI OIDC login with Authentik requires entering credentials twice (prompt=login re-triggers full auth flow within the same authorization request)

Issue Description

Environment

  • Stalwart version: v0.16.19
  • OIDC provider: Authentik (self-hosted)
  • Directory config: type Oidc, client_type “public” on the Authentik side, PKCE (S256)
  • Directory settings (Stalwart side): claimUsername=email, requireScopes={openid, email, profile}, requireAudience=stalwart-webui

Problem
Logging into the Stalwart WebUI (admin panel, “Login with SSO”) via an Authentik OIDC directory requires entering the password twice for a single login attempt. TOTP is only requested on the first pass. Reproduced consistently, including in a fresh private/incognito browser window (rules out stale cookies/session state).

Evidence from Authentik’s event log (redacted)

Authorization request as sent by Stalwart’s WebUI:
/application/o/authorize/?response_type=code&client_id=stalwart-webui&redirect_uri=https%3A%2F%2Fmail.example.com%2Faccount%2Foauth%2Fcallback&code_challenge=9CRVSr0uP3C9aRN7siIrIMAovq4qnCk1rDM8OVSFxI0&code_challenge_method=S256&state=c6c36a9911a7f31cbba49c5a7b139fd4&login_hint=user%40example.com&prompt=login&scope=openid+email+profile

Resulting Authentik events, all tied to the same state/code_challenge (i.e. the same authorization request):

Stalwart Version

v0.16.x

Installation Method

Binary (Linux)

Database Backend

RocksDB

Blob Storage

RocksDB

Search Engine

Internal

Directory Backend

Internal

I have reviewed the documentation and FAQ and confirm that my issue is NOT addressed there.

on

I have searched this support forum (open and closed topics) and confirm this is not a duplicate.

on

I understand that topics in this category are triaged by a bot first but a human reply will follow up. If I’d prefer a human-only reply, I’ll add the no-ai tag to my topic.

on

The WebUI’s OIDC login flow always includes prompt=login in the authorization request. Looking at the source, this is intentional and hardcoded, not configurable: every “Login with SSO” attempt forces the identity provider to fully re-authenticate the user rather than reusing an existing IdP session, even in the same browser/session (webui/src/services/auth/oauth.ts, the startAuthFlow function always sets prompt: 'login').

That said, prompt=login is only supposed to force one full re-authentication in response to a single authorization request; it isn’t expected to trigger two separate authentication sequences within the same request. The behavior you’re seeing, where Authentik appears to run the credential+TOTP challenge and then a second credential-only challenge tied to the same state/code_challenge, is not something documented as expected Stalwart behavior, and there is no configuration flag currently exposed to change or disable the prompt=login parameter.

This isn’t covered in the current docs. A community member or staff member will follow up.

This is an automated reply from the Stalwart Help Bot. Other community members may follow up if this answer is incomplete or wrong.

We send one authorization request, and prompt=login appears in it once. Nothing on our side can ask Authentik to authenticate twice: the parameter is built client-side in the WebUI (src/services/auth/oauth.ts:154) and only the one request goes out.

It is there so the account typed into our login box is the one that authenticates, without silently reusing whatever IdP session the browser already holds. OIDC Core is explicit that an OP receiving prompt=login must reauthenticate the end user, once, not run its flow twice.

Your post cuts off right before the Authentik event list (“Resulting Authentik events” is empty), so I have not seen the sequence. Can you paste it, along with which authorization flow the stalwart-webui provider uses and whether the brand’s default authentication flow is a different one? A test you can run yourself: take that same authorize URL, delete &prompt=login from it, and open it in a fresh private window. If one password entry suffices there, Authentik’s handling of the parameter is where it doubles up.

We do not expose prompt=login as a setting today. Also, set the log level to trace and check your logs.

1. Provider flow configuration

The Stalwart OAuth2 provider in Authentik has:

  • authorization_flow: default-provider-authorization-implicit-consent (designation: authorization — this is just the consent/“allow app” step)
  • authentication_flow: not set (null) on the provider itself

Since the provider doesn’t override the authentication flow, it falls back to the Brand’s default: default-authentication-flow (“Welcome to authentik!”). This is the same flow used for every other login on this Authentik instance — there is no separate/different flow bound specifically to the Stalwart provider. Flow stages (all re_evaluate_policies=true): identification → password → mfa-validation → login.

2. Full event sequence (sorry, this got cut off in my original post)

All three events below share the same authorization request (state=c6c36a9911a7f31cbba49c5a7b139fd4, code_challenge=9CRVSr0uP3C9aRN7siIrIMAovq4qnCk1rDM8OVSFxI0):

13:24:55.280  model_updated   TOTP Authenticator stage completed, user: <redacted>
13:24:55.449  login           auth_method=password, SUCCESS, user: <redacted>
13:25:02.026  login_failed    stage: default-authentication-password, user: <redacted>

3. Your suggested test

Removed &prompt=login, fresh private window: no double challenge, but also no visible login screen at all — likely silently reused an existing session in that profile. Can re-test with a guaranteed clean session if that distinction matters.

4. Trace-level Stalwart logs

Set the tracer to trace, reproduced the double-prompt. Zero oauth/oidc-related lines on Stalwart’s side for the whole incident — the failing second challenge never reaches Stalwart’s backend at all, it’s fully internal to Authentik.

Ask your LLM to look at the logs and your OIDC settings. The double login screen is happening because something is wrong while validating the token. We won’t know until you provide the logs.