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