Svelte
If you would like to integrate Scute authentication with your Svelte app, you can do so using the @scute/js-core
package. This approach gives you full control over the authentication flow and allows you to build custom UI components that match your app's design.
Head over to the example project repo to check out the complete Svelte example and see how all the components work together.
To get started, install the Scute core SDK with your favorite package manager:
npm install @scute/js-core
Add your credentials to your environment variable handler:
VITE_SCUTE_APP_ID="YOUR_SCUTE_PROJECT_ID"
VITE_SCUTE_BASE_URL="YOUR_SCUTE_BASE_URL"
Initialize the Scute client
First initialize the Scute client using the createClient
method exposed by @scute/js-core
package:
// scute.ts
import { createClient } from "@scute/js-core";
export const scuteClient = createClient({
appId: import.meta.env.VITE_SCUTE_APP_ID,
baseUrl: import.meta.env.VITE_SCUTE_BASE_URL,
});
Create your main App component
Create your main App.svelte
component that handles the authentication flow:
<!-- App.svelte -->
<script lang="ts">
import { onMount } from 'svelte';
import {
getMeaningfulError,
SCUTE_MAGIC_PARAM,
SCUTE_SKIP_PARAM,
type ScuteTokenPayload,
type ScuteUserData,
} from "@scute/js-core";
import { scuteClient } from './scute';
import LoginForm from './lib/LoginForm.svelte';
import MagicSent from './lib/MagicSent.svelte';
import MagicVerify from './lib/MagicVerify.svelte';
import OtpForm from './lib/OtpForm.svelte';
import RegisterDevice from './lib/RegisterDevice.svelte';
import Profile from './lib/Profile.svelte';
let identifier = '';
let component = '';
let magicLinkToken: string | null = null;
let tokenPayload: ScuteTokenPayload | null = null;
// Catch magic link token from url if it exists and verify it
// OAuth token is also a magic link token and will be handled by this block.
onMount(() => {
const token = scuteClient.getMagicLinkToken();
if (token) {
component = 'magic_verify';
magicLinkToken = token;
return;
}
// Check existing session on app load
const getSession = async () => {
const { data, error } = await scuteClient.getSession();
if (error) {
console.error(error);
}
if (data?.session && data.session.status === "authenticated") {
component = "profile";
} else {
component = "login";
}
};
getSession();
});
function setComponent(newComponent: string) {
component = newComponent;
}
function setIdentifier(newIdentifier: string) {
identifier = newIdentifier;
}
function setTokenPayload(newTokenPayload: ScuteTokenPayload | null) {
tokenPayload = newTokenPayload;
}
function setMagicLinkToken(token: string | null) {
magicLinkToken = token;
}
</script>
<main class="app">
{#if component === "profile"}
<Profile {setComponent} />
{:else if component === "login"}
<LoginForm {scuteClient} {identifier} {setIdentifier} {setComponent} />
{:else if component === "magic_verify"}
<MagicVerify {scuteClient} {magicLinkToken} {setTokenPayload} {setComponent} />
{:else if component === "magic_sent"}
<MagicSent {identifier} />
{:else if component === "register_device"}
<RegisterDevice {scuteClient} {tokenPayload} {setComponent} />
{:else if component === "otp_verify"}
<OtpForm {scuteClient} {identifier} {setComponent} {setTokenPayload} />
{/if}
</main>
<style>
.app {
display: flex;
flex-direction: column;
gap: 32px;
align-items: center;
justify-content: center;
min-height: 100vh;
padding: 2rem;
}
</style>
Create a Login component
Create a LoginForm.svelte
component for handling user authentication:
<!-- lib/LoginForm.svelte -->
<script lang="ts">
import { getMeaningfulError, type ScuteClient } from "@scute/js-core";
export let scuteClient: ScuteClient;
export let identifier: string;
export let setIdentifier: (identifier: string) => void;
export let setComponent: (component: string) => void;
async function handleSubmit(e: Event) {
e.preventDefault();
const { data, error } = await scuteClient.signInOrUp(identifier);
if (error) {
console.log("signInOrUp error", getMeaningfulError(error));
return;
}
if (!data) {
// passkey verified.
setComponent("profile");
} else {
if (identifier.includes("@")) {
setComponent("magic_sent");
} else {
setComponent("otp_verify");
}
}
}
</script>
<div class="login-form">
<h1>Sign In</h1>
<form on:submit={handleSubmit}>
<input
type="text"
placeholder="Email or phone number"
bind:value={identifier}
required
/>
<button type="submit">Continue</button>
</form>
</div>
<style>
.login-form {
max-width: 400px;
padding: 2rem;
border: 1px solid #ddd;
border-radius: 8px;
}
input {
width: 100%;
padding: 0.75rem;
margin: 0.5rem 0;
border: 1px solid #ddd;
border-radius: 4px;
}
button {
width: 100%;
padding: 0.75rem;
background: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background: #0056b3;
}
</style>
Create a Profile component
Create a Profile.svelte
component for authenticated users:
<!-- lib/Profile.svelte -->
<script lang="ts">
import { onMount } from 'svelte';
import { type ScuteUserData } from "@scute/js-core";
import { scuteClient } from '../scute';
export let setComponent: (component: string) => void;
let user: ScuteUserData | null = null;
onMount(() => {
const getSession = async () => {
const { data, error } = await scuteClient.getSession();
if (error) {
console.error(error);
}
if (!data?.session || data.session.status === "unauthenticated") {
setComponent("login");
} else {
user = data.user;
}
};
getSession();
});
async function handleSignOut() {
await scuteClient.signOut();
setComponent("login");
}
</script>
{#if user}
<div class="profile">
<h1>Welcome!</h1>
<p>User ID: {user.id}</p>
<p>Email: {user.email || 'N/A'}</p>
<p>Phone: {user.phoneNumber || 'N/A'}</p>
<button on:click={handleSignOut}>Sign Out</button>
</div>
{:else}
<div>Loading...</div>
{/if}
<style>
.profile {
max-width: 400px;
padding: 2rem;
border: 1px solid #ddd;
border-radius: 8px;
text-align: center;
}
button {
padding: 0.75rem 1.5rem;
background: #dc3545;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-top: 1rem;
}
button:hover {
background: #c82333;
}
</style>
Additional Components
The example also includes additional components for handling different authentication flows:
MagicVerify.svelte
- For verifying magic link tokensMagicSent.svelte
- Shows confirmation when magic link is sentOtpForm.svelte
- For OTP verification (SMS/phone)RegisterDevice.svelte
- For WebAuthn device registration
You can find the complete implementation of these components in the example repository.
Running the Example
- Clone the example repository
- Copy
env.example
to.env
and add your credentials - Install dependencies:
npm install
- Start the development server:
npm run dev
Congrats! You now have a working Scute authentication system in your Svelte app!
Core Methods
The scuteClient
provides several methods for authentication:
signInOrUp(identifier: string)
Initiates the sign-in or sign-up process with an email or phone number.
getSession()
Retrieves the current user session and user data.
signOut()
Signs out the current user and clears the session.
getMagicLinkToken()
Extracts magic link tokens from the current URL for verification.
verifyMagicLink(token: string)
Verifies a magic link token and completes authentication.
For more methods and detailed API documentation, check out the type docs.