Skip to content

Commit da8a495

Browse files
authored
fix(auth): use dynamic imports for @simplewebauthn/browser to fix SSR (#43)
The @simplewebauthn/browser package is browser-only and cannot be imported at the module level in SvelteKit components that undergo SSR. Replace static imports with dynamic import() inside onMount callbacks to ensure the package is only loaded client-side. Fixes the /auth/login 500 error on the tinyland deployment.
1 parent 96f5102 commit da8a495

File tree

2 files changed

+13
-5
lines changed

2 files changed

+13
-5
lines changed

app/src/lib/components/auth/PasskeyManager.svelte

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script lang="ts">
2-
import { browserSupportsWebAuthn, startRegistration } from '@simplewebauthn/browser';
2+
import { onMount } from 'svelte';
33
44
let { authMethod = 'oauth' }: { authMethod: string } = $props();
55
@@ -15,8 +15,11 @@
1515
let loading = $state(true);
1616
let registering = $state(false);
1717
let error = $state('');
18+
let webauthnSupported = $state(false);
1819
19-
$effect(() => {
20+
onMount(async () => {
21+
const { browserSupportsWebAuthn } = await import('@simplewebauthn/browser');
22+
webauthnSupported = browserSupportsWebAuthn();
2023
loadPasskeys();
2124
});
2225
@@ -38,6 +41,8 @@
3841
registering = true;
3942
error = '';
4043
try {
44+
const { startRegistration } = await import('@simplewebauthn/browser');
45+
4146
const optionsRes = await fetch('/auth/webauthn/register');
4247
if (!optionsRes.ok) {
4348
throw new Error('Failed to get registration options');
@@ -87,7 +92,7 @@
8792
});
8893
}
8994
90-
const canRegister = $derived(authMethod === 'oauth' && browserSupportsWebAuthn());
95+
const canRegister = $derived(authMethod === 'oauth' && webauthnSupported);
9196
</script>
9297

9398
<div class="space-y-3">

app/src/routes/auth/login/+page.svelte

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,21 @@
11
<script lang="ts">
2-
import { browserSupportsWebAuthn, startAuthentication } from '@simplewebauthn/browser';
2+
import { onMount } from 'svelte';
33
44
let webauthnSupported = $state(false);
55
let webauthnLoading = $state(false);
66
let webauthnError = $state('');
77
8-
$effect(() => {
8+
onMount(async () => {
9+
const { browserSupportsWebAuthn } = await import('@simplewebauthn/browser');
910
webauthnSupported = browserSupportsWebAuthn();
1011
});
1112
1213
async function loginWithPasskey() {
1314
webauthnLoading = true;
1415
webauthnError = '';
1516
try {
17+
const { startAuthentication } = await import('@simplewebauthn/browser');
18+
1619
const optionsRes = await fetch('/auth/webauthn/authenticate');
1720
const options = await optionsRes.json();
1821

0 commit comments

Comments
 (0)