feat(web): /auth/reset + /auth/verify als Fallback-Pages
Some checks are pending
CI / validate (push) Waiting to run
Some checks are pending
CI / validate (push) Waiting to run
Wenn der Reset-Link aus der Email auf einem Gerät ohne installierte
Cardecky-iOS-App geöffnet wird (Desktop, Android, iOS-ohne-App),
fängt Apple den Universal-Link nicht ab — der Browser landet auf
cardecky.mana.how/auth/reset. Heute = 404.
Diese minimalen Brücken redirecten den Token an die jeweilige
auth.mana.how-Surface, damit der Reset/Verify-Flow trotzdem durchläuft:
cardecky.mana.how/auth/reset?token=X
→ auth.mana.how/reset-password?token=X (Web-Reset-Formular)
cardecky.mana.how/auth/verify?token=X
→ auth.mana.how/api/auth/verify-email?token=X (Better-Auth-Endpoint)
iOS mit installierter App: Universal-Link greift, Browser-Page wird
nie gerendert.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8c7c8c9c98
commit
eb39faddb3
2 changed files with 128 additions and 0 deletions
69
apps/web/src/routes/auth/reset/+page.svelte
Normal file
69
apps/web/src/routes/auth/reset/+page.svelte
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { page } from '$app/state';
|
||||
import { env as publicEnv } from '$env/dynamic/public';
|
||||
|
||||
/**
|
||||
* Web-Fallback für die Reset-Password-Mail von mana-auth.
|
||||
*
|
||||
* Auf iOS-Geräten mit installierter Cardecky-App öffnet Apple den
|
||||
* Universal Link direkt in der App, diese Page wird nie gerendert.
|
||||
*
|
||||
* Für alle anderen User (kein iOS, App nicht installiert, Desktop)
|
||||
* leiten wir zum Web-Auth-Portal weiter, das den gleichen Token
|
||||
* akzeptiert und ein Web-Reset-Formular zeigt.
|
||||
*/
|
||||
let phase = $state<'redirecting' | 'no-token' | 'error'>('redirecting');
|
||||
|
||||
function authWebUrl(): string {
|
||||
return publicEnv.PUBLIC_AUTH_WEB_URL ?? 'https://auth.mana.how';
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
const token = page.url.searchParams.get('token');
|
||||
if (!token) {
|
||||
phase = 'no-token';
|
||||
return;
|
||||
}
|
||||
const target = new URL(`${authWebUrl()}/reset-password`);
|
||||
target.searchParams.set('token', token);
|
||||
window.location.replace(target.toString());
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Passwort zurücksetzen — Cardecky</title>
|
||||
</svelte:head>
|
||||
|
||||
<main class="container">
|
||||
{#if phase === 'redirecting'}
|
||||
<p>Weiterleitung zum Reset-Formular…</p>
|
||||
{:else if phase === 'no-token'}
|
||||
<h1>Link unvollständig</h1>
|
||||
<p>
|
||||
Der Reset-Link enthält keinen Token. Bitte klicke den Link aus deiner
|
||||
Bestätigungs-Mail erneut oder fordere einen neuen an.
|
||||
</p>
|
||||
<p><a href={authWebUrl() + '/forgot-password'}>Neuen Reset-Link anfordern</a></p>
|
||||
{:else}
|
||||
<h1>Fehler</h1>
|
||||
<p>Etwas ist schiefgelaufen. Bitte versuche es später erneut.</p>
|
||||
{/if}
|
||||
</main>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
max-width: 480px;
|
||||
margin: 64px auto;
|
||||
padding: 24px;
|
||||
text-align: center;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
a {
|
||||
color: var(--primary, #2563eb);
|
||||
}
|
||||
</style>
|
||||
59
apps/web/src/routes/auth/verify/+page.svelte
Normal file
59
apps/web/src/routes/auth/verify/+page.svelte
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { page } from '$app/state';
|
||||
import { env as publicEnv } from '$env/dynamic/public';
|
||||
|
||||
/**
|
||||
* Web-Fallback für die Verify-Email-Mail von mana-auth.
|
||||
*
|
||||
* Auf iOS-Geräten mit installierter Cardecky-App öffnet Apple den
|
||||
* Universal Link direkt in der App. Für alle anderen User leiten
|
||||
* wir zum Better-Auth-Verify-Endpoint auf auth.mana.how weiter,
|
||||
* der den Token konsumiert und auf das Auth-Portal redirected.
|
||||
*/
|
||||
let phase = $state<'redirecting' | 'no-token'>('redirecting');
|
||||
|
||||
function authWebUrl(): string {
|
||||
return publicEnv.PUBLIC_AUTH_WEB_URL ?? 'https://auth.mana.how';
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
const token = page.url.searchParams.get('token');
|
||||
if (!token) {
|
||||
phase = 'no-token';
|
||||
return;
|
||||
}
|
||||
// Better Auths Verify-Endpoint nimmt den Token aus dem Query
|
||||
// und setzt nach Erfolg die Email-Verified-Flag in der DB.
|
||||
const target = new URL(`${authWebUrl()}/api/auth/verify-email`);
|
||||
target.searchParams.set('token', token);
|
||||
window.location.replace(target.toString());
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Email bestätigen — Cardecky</title>
|
||||
</svelte:head>
|
||||
|
||||
<main class="container">
|
||||
{#if phase === 'redirecting'}
|
||||
<p>Email wird bestätigt…</p>
|
||||
{:else}
|
||||
<h1>Link unvollständig</h1>
|
||||
<p>Der Verify-Link enthält keinen Token. Bitte klicke den Link aus der Mail erneut.</p>
|
||||
{/if}
|
||||
</main>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
max-width: 480px;
|
||||
margin: 64px auto;
|
||||
padding: 24px;
|
||||
text-align: center;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
}
|
||||
h1 {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
</style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue