fix(login): provide a postError redirect url for idp flows (#10883)

# Which Problems Are Solved

Improves the user experience when IDP authentication succeeds but user
creation/linking fails by introducing a `postErrorRedirectUrl` parameter
and dedicated error pages instead of generic error screens.

<img width="580" height="636" alt="Screenshot 2025-10-16 at 09 21 07"
src="https://github.com/user-attachments/assets/db653c8f-b648-4cfe-922a-2f237f3b70b3"
/>

# How the Problems Are Solved

## New Pages
- **`/idp/[provider]/account-not-found`**: Displayed when no user
account exists and creation/linking is not allowed
- **`/idp/[provider]/registration-failed`**: Displayed when user
registration fails due to organization resolution issues

## Flow Improvements
- Added `postErrorRedirectUrl` parameter to track where the IDP flow was
initiated
- Each entry point (loginname, register, idp, authenticator/set)
specifies its own redirect URL
- Users are now redirected to appropriate error pages with clear
messaging instead of generic error screens
- All context (`requestId`, `organization`, `postErrorRedirectUrl`) is
preserved throughout the flow

## Updated Components
- `SignInWithIdp`: Now accepts and passes `postErrorRedirectUrl`
parameter
- `redirectToIdp` server action: Extracts and forwards
`postErrorRedirectUrl` through the IDP flow
- IDP success page: Routes to appropriate error pages based on failure
reason

## i18n
Added new translation keys:
- `idp.accountNotFound.*` - For missing account scenarios
- `idp.registrationFailed.*` - For organization resolution failures
This commit is contained in:
Max Peintner
2025-10-16 11:24:54 +02:00
committed by GitHub
parent 19b744ca67
commit 00beaf6ddc
15 changed files with 515 additions and 5 deletions
@@ -20,6 +20,7 @@ export interface SignInWithIDPProps {
requestId?: string;
organization?: string;
linkOnly?: boolean;
postErrorRedirectUrl?: string;
showLabel?: boolean;
}
@@ -28,6 +29,7 @@ export function SignInWithIdp({
requestId,
organization,
linkOnly,
postErrorRedirectUrl,
showLabel = true,
}: Readonly<SignInWithIDPProps>) {
const [state, action, _isPending] = useActionState(redirectToIdp, {});
@@ -58,6 +60,7 @@ export function SignInWithIdp({
<input type="hidden" name="requestId" value={requestId} />
<input type="hidden" name="organization" value={organization} />
<input type="hidden" name="linkOnly" value={linkOnly ? "true" : "false"} />
{postErrorRedirectUrl && <input type="hidden" name="postErrorRedirectUrl" value={postErrorRedirectUrl} />}
<Component key={id} name={name} />
</form>
) : null;