mirror of
https://github.com/pocket-id/pocket-id.git
synced 2026-05-19 03:19:53 +00:00
feat: add support for "select_account" prompt (#1453)
Co-authored-by: Elias Schneider <login@eliasschneider.com>
This commit is contained in:
committed by
GitHub
parent
e33a9b8c88
commit
f4706cd6cc
@@ -53,6 +53,8 @@
|
||||
"webauthn_not_supported_by_browser": "Passkeys are not supported by this browser. Please use an alternative sign in method.",
|
||||
"critical_error_occurred_contact_administrator": "A critical error occurred. Please contact your administrator.",
|
||||
"sign_in_to": "Sign in to {name}",
|
||||
"account_selection_signin_confirmation": "Do you want to use the following account to continue to <b>{name}</b>?",
|
||||
"use_a_different_account": "Use a different account",
|
||||
"client_not_found": "Client not found",
|
||||
"client_wants_to_access_the_following_information": "<b>{client}</b> wants to access the following information:",
|
||||
"do_you_want_to_sign_in_to_client_with_your_app_name_account": "Do you want to sign in to <b>{client}</b> with your {appName} account?",
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
<div class=" w-full {isAuthPage ? 'absolute top-0 z-10 mt-3 lg:mt-8 pr-2 lg:pr-3' : 'border-b'}">
|
||||
<div
|
||||
class="{!isAuthPage
|
||||
? 'max-w-[1640px]'
|
||||
? 'max-w-410'
|
||||
: ''} mx-auto flex w-full items-center justify-between px-4 md:px-10"
|
||||
>
|
||||
<div class="flex h-16 items-center">
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<script lang="ts">
|
||||
import { invalidateAll } from '$app/navigation';
|
||||
import FormattedMessage from '$lib/components/formatted-message.svelte';
|
||||
import SignInWrapper from '$lib/components/login-wrapper.svelte';
|
||||
import ScopeList from '$lib/components/scope-list.svelte';
|
||||
import * as Avatar from '$lib/components/ui/avatar';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import { m } from '$lib/paraglide/messages';
|
||||
@@ -9,6 +11,7 @@
|
||||
import WebAuthnService from '$lib/services/webauthn-service';
|
||||
import appConfigStore from '$lib/stores/application-configuration-store';
|
||||
import userStore from '$lib/stores/user-store';
|
||||
import { cachedProfilePicture } from '$lib/utils/cached-image-util';
|
||||
import { getWebauthnErrorMessage } from '$lib/utils/error-util';
|
||||
import { startAuthentication, type AuthenticationResponseJSON } from '@simplewebauthn/browser';
|
||||
import { onMount } from 'svelte';
|
||||
@@ -37,8 +40,22 @@
|
||||
let errorMessage: string | null = $state(null);
|
||||
let authorizationRequired = $state(false);
|
||||
let authorizationConfirmed = $state(false);
|
||||
let accountSelectionRequired = $state(false);
|
||||
let userSignedInAt: Date | undefined;
|
||||
|
||||
const fullName = $derived.by(() => {
|
||||
if (!$userStore) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($userStore.displayName) {
|
||||
return $userStore.displayName;
|
||||
}
|
||||
|
||||
return [$userStore.firstName, $userStore.lastName].filter(Boolean).join(' ').trim();
|
||||
});
|
||||
const primaryName = $derived(fullName || $userStore?.email || '');
|
||||
|
||||
// Parse prompt parameter once (space-delimited per OIDC spec)
|
||||
const promptValues = prompt ? prompt.split(' ') : [];
|
||||
const hasPromptNone = promptValues.includes('none');
|
||||
@@ -59,11 +76,27 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// prompt=select_account: if the user is already signed in, pause so they can
|
||||
// confirm the current account before proceeding. If they're not signed in,
|
||||
// the normal login flow below is selection enough.
|
||||
if (hasPromptSelectAccount && $userStore) {
|
||||
accountSelectionRequired = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($userStore) {
|
||||
authorize();
|
||||
}
|
||||
});
|
||||
|
||||
async function useDifferentAccount() {
|
||||
try {
|
||||
await webauthnService.logout();
|
||||
} finally {
|
||||
await invalidateAll();
|
||||
}
|
||||
}
|
||||
|
||||
async function authorize() {
|
||||
isLoading = true;
|
||||
|
||||
@@ -227,7 +260,39 @@
|
||||
{errorMessage}.
|
||||
</p>
|
||||
{/if}
|
||||
{#if !authorizationRequired && !errorMessage}
|
||||
{#if accountSelectionRequired && $userStore && !errorMessage}
|
||||
<div transition:slide={{ duration: 300 }} class="flex flex-col items-center">
|
||||
<p class="text-muted-foreground mt-2 mb-8">
|
||||
<FormattedMessage m={m.account_selection_signin_confirmation({ name: client.name })} />
|
||||
</p>
|
||||
<Card.Root class="mb-2 py-4 w-sm" data-testid="account-selection">
|
||||
<Card.Content class="flex items-center gap-4">
|
||||
<Avatar.Root class="size-11 shrink-0">
|
||||
<Avatar.Image src={cachedProfilePicture.getUrl($userStore.id)} />
|
||||
</Avatar.Root>
|
||||
<div class="flex min-w-0 flex-col text-start">
|
||||
<p class="truncate text-base leading-tight font-medium">
|
||||
{primaryName}
|
||||
</p>
|
||||
{#if fullName && $userStore.email}
|
||||
<p class="text-muted-foreground mt-1 truncate text-sm leading-tight">
|
||||
{$userStore.email}
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
<div class="mb-10 flex justify-center">
|
||||
<button
|
||||
type="button"
|
||||
class="text-muted-foreground text-xs transition-colors hover:underline"
|
||||
onclick={useDifferentAccount}
|
||||
>
|
||||
{m.use_a_different_account()}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{:else if !authorizationRequired && !errorMessage}
|
||||
<p class="text-muted-foreground mt-2 mb-10">
|
||||
<FormattedMessage
|
||||
m={m.do_you_want_to_sign_in_to_client_with_your_app_name_account({
|
||||
|
||||
Reference in New Issue
Block a user