<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Berzan</title>
    <description>The latest articles on DEV Community by Berzan (@bmikaili).</description>
    <link>https://dev.to/bmikaili</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1063812%2F5790469e-a252-4b08-a702-f1518a861c5c.png</url>
      <title>DEV Community: Berzan</title>
      <link>https://dev.to/bmikaili</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bmikaili"/>
    <language>en</language>
    <item>
      <title>Building a SvelteKit Demo Page with Web Component and Passkey Login for passkeys.eu</title>
      <dc:creator>Berzan</dc:creator>
      <pubDate>Wed, 12 Apr 2023 14:23:46 +0000</pubDate>
      <link>https://dev.to/corbado/building-a-sveltekit-demo-page-with-web-component-and-passkey-login-using-corbadocom-1ci4</link>
      <guid>https://dev.to/corbado/building-a-sveltekit-demo-page-with-web-component-and-passkey-login-using-corbadocom-1ci4</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;1. Introduction&lt;/li&gt;
&lt;li&gt;2. Setting up the SvelteKit project&lt;/li&gt;
&lt;li&gt;3. Setting up fonts and global styles using Tailwind&lt;/li&gt;
&lt;li&gt;4. Repository structure&lt;/li&gt;
&lt;li&gt;
5. Setting up the Corbado web component for passkey authentication

&lt;ul&gt;
&lt;li&gt;5.1 Setting up your Corbado account and project&lt;/li&gt;
&lt;li&gt;5.2 Including the web component in our frontend&lt;/li&gt;
&lt;li&gt;5.3 Setting up the redirect logic&lt;/li&gt;
&lt;li&gt;5.4 Using cookies to manage authentication state&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;6. Conclusion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  1. Introduction
&lt;/h2&gt;

&lt;p&gt;In this blog post, we'll be walking through the process of building a demo page for &lt;a href="https://passkeys.eu/"&gt;passkeys.eu&lt;/a&gt; using SvelteKit. We'll cover how to create a reusable web component and implement passkey login functionality for a seamless user experience. This tutorial assumes basic familiarity with SvelteKit, HTML, CSS and JavaScript. Let's dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Setting up the SvelteKit project
&lt;/h2&gt;

&lt;p&gt;We'll follow along by cloning our &lt;a href="https://github.com/Corbado/passkeys-demo"&gt;demo repository&lt;/a&gt; with the finished code, but in case you are interested in how you'd set up the skeleton of the project, check out the next 2 sections. Otherwise, you can skip them and continue from repository structure.&lt;/p&gt;

&lt;p&gt;We will be using &lt;a href="https://flowbite-svelte.com/pages/getting-started"&gt;Flowbite&lt;/a&gt;, which is a component library based on &lt;a href="https://tailwindcss.com"&gt;TailwindCSS&lt;/a&gt; to quickly build a responsive and aesthetic UI.&lt;br&gt;
Let's start out by installing SvelteKit. We are going to use &lt;a href="https://pnpm.io"&gt;pnpm&lt;/a&gt; instead of &lt;code&gt;npm&lt;/code&gt;, as &lt;code&gt;pnpm&lt;/code&gt; is faster by using symlinks to reuse existing dependencies. To install &lt;code&gt;pnpm&lt;/code&gt;, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; pnpm
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we've done that, we can install SvelteKit and initialize our project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm create svelte@latest passkeys-demo
&lt;span class="nb"&gt;cd &lt;/span&gt;passkeys-demo
pnpm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we'll have to install TailwindCSS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpx svelte-add@latest tailwindcss
pnpm i
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we'll have to install Flowbite's svelte library&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pnpm i flowbite flowbite-svelte classnames @popperjs/core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, we'll update our &lt;code&gt;tailwind.config.cjs&lt;/code&gt; to include Flowbite:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/**/*.{html,js,svelte,ts}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./node_modules/flowbite-svelte/**/*.{html,js,svelte,ts}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;

    &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;

    &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flowbite/plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)],&lt;/span&gt;
    &lt;span class="na"&gt;darkMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;class&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Setting up fonts and global styles using Tailwind
&lt;/h2&gt;

&lt;p&gt;To set up some standard fonts and styles that should be global for our application, we can use Tailwind theming. First, we'll create a &lt;code&gt;&amp;lt;svelte:head&amp;gt;&lt;/code&gt; section in our root &lt;code&gt;+page.svelte&lt;/code&gt;. This behaves like a standard HTML &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; you'd find in the &lt;code&gt;index.html&lt;/code&gt; file, it contains metadata and allows you to include third party scripts. We are going to use it to include some fonts from &lt;a href="https://fonts.bunny.net/"&gt;Bunny Fonts&lt;/a&gt; and add some metadata for SEO. Add this to your &lt;code&gt;+page.svelte&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;svelte:head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"preconnect"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.bunny.net"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.bunny.net/css?family=inter:500|space-grotesk:500"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Passkeys demo&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Corbado Passkey passwordless authentication demo"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svelte:head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Repository structure
&lt;/h2&gt;

&lt;p&gt;Let's first discuss the structure of our &lt;code&gt;src&lt;/code&gt; folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;├── lib
│  ├── assets
│  │  ├── apple.svg
│  │  ├── auth-sample.svg
│  │  ├── Corbado.png
│  │  ├── devices.svg
│  │  ├── europe.png
│  │  ├── github.png
│  │  ├── google.svg
│  │  ├── microsoft.svg
│  │  ├── slack.webp
│  │  └── twitter.png
│  ├── components
│  │  ├── CheckItem.svelte
│  │  └── InfoCard.svelte
│  └── sections
│     ├── Footer.svelte
│     ├── PasskeyDemo.svelte
│     ├── PasskeyExplainer.svelte
│     ├── PasskeySaas.svelte
│     ├── PasskeyStats.svelte
│     └── PasskeyTimeline.svelte
├── routes
│  ├── api
│  │  ├── &lt;span class="nb"&gt;logout&lt;/span&gt;
│  │  │  └── +server.ts
│  │  └── register
│  │     └── +server.ts
│  ├── +layout.svelte
│  ├── +page.server.ts
│  └── +page.svelte
├── app.d.ts
├── app.html
└── app.postcss
 static
└── favicon.png
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;lib&lt;/code&gt; contains auxiliary files, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;image &lt;code&gt;assets&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;custom &lt;code&gt;components&lt;/code&gt; we made&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sections&lt;/code&gt; that we use on our demo page&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;

&lt;p&gt;&lt;code&gt;routes&lt;/code&gt; contains all the routes of our app, such as&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;api&lt;/code&gt; routes, these are equivalent to API endpoints you would have in a classic server / backend. The path of the endpoints correspond to their folder path.&lt;/li&gt;
&lt;li&gt;The root path &lt;code&gt;/&lt;/code&gt; svelte files:&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;+layout.svelte&lt;/code&gt; defines the overall layout and applies our global &lt;code&gt;.postcss&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;+page.server.ts&lt;/code&gt; handles server-side logic for that particular route (&lt;code&gt;/&lt;/code&gt; in this case), such as load functions or form actions.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;+page.svelte&lt;/code&gt; contains the actual client-side code to render our page&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We have a root &lt;code&gt;.html&lt;/code&gt; and &lt;code&gt;.css&lt;/code&gt; file, which we can ignore for the purpose of our tutorial. And a &lt;code&gt;static&lt;/code&gt; folder for assets like favicons.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Setting up the Corbado web component for passkey authentication
&lt;/h2&gt;

&lt;p&gt;Our demo page contains various sections as defined in our &lt;code&gt;+page.svelte&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"ts"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Footer&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$lib/sections/Footer.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PasskeyDemo&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$lib/sections/PasskeyDemo.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PasskeyExplainer&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$lib/sections/PasskeyExplainer.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PasskeySaas&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$lib/sections/PasskeySaas.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PasskeyStats&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$lib/sections/PasskeyStats.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PasskeyTimeline&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$lib/sections/PasskeyTimeline.svelte&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PageData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./$types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PageData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;svelte:head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"preconnect"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.bunny.net"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://fonts.bunny.net/css?family=inter:500|space-grotesk:500"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Corbado Passkey demo&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Corbado Passkey passwordless authentication demo"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svelte:head&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;PasskeyDemo&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;PasskeyExplainer&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;PasskeyTimeline&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;PasskeyStats&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;PasskeySaas&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;footer&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the purpose of this demo, we'll focus on integrating Corbado, so I am going to omit on how I styled and built those pages. If you're interested, checkout the &lt;code&gt;src/lib/sections&lt;/code&gt; and &lt;code&gt;src/lib/components&lt;/code&gt; folder in the project repository to see how they're styled.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.1 Setting up your Corbado account and project
&lt;/h3&gt;

&lt;p&gt;Visit the &lt;a href="https://app.corbado.com/signin#register"&gt;Corbado Developer Panel&lt;/a&gt; to sign up and create your account (you'll see passkeys sign up in action!).&lt;br&gt;
Once you are in the developer panel, go to Settings &amp;gt; Credentials:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Press on &lt;code&gt;Add New&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here, add a new authorized origin so that your local Svelte app can send requests to the Corbado API using the web component:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter a name description, e.g. "Passkey demo"&lt;/li&gt;
&lt;li&gt;Enter the origin URL, in our case the &lt;code&gt;http://localhost:5137&lt;/code&gt; local url&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you are done, you will need to get your project ID and create an API secret to authenticate with the Corbado backend. Go to the &lt;code&gt;API secrets&lt;/code&gt; tab.&lt;/p&gt;

&lt;p&gt;Copy the username by clicking on it, and press on add new to get a new API secret you can copy. We'll add these to an &lt;code&gt;.env&lt;/code&gt; file in the root of our SvelteKit project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;CORBADO_API_SECRET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;****&lt;/span&gt;
&lt;span class="nv"&gt;PUBLIC_CORBADO_PROJECT_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;***&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SvelteKit allows us to easily access these using the $env namespace to import them. Env variables with &lt;code&gt;PUBLIC_&lt;/code&gt; prefix are accessible in both client and server routes, while ones without default to being secret and are only accessible in SvelteKit server routes.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.2 Including the web component in our frontend
&lt;/h3&gt;

&lt;p&gt;The first section in our root &lt;code&gt;+page.svelte&lt;/code&gt; is &lt;code&gt;PasskeysDemo&lt;/code&gt;. This section contains our web component demo. To import the Corbado web component into our app, all we need to do is add a &lt;code&gt;svelte:head&lt;/code&gt; to load the script in &lt;code&gt;src/lib/sections/PasskeyDemo.svelte&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;svelte:head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;defer&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://auth.Corbado.com/auth.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svelte:head&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can include it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Corbado-auth&lt;/span&gt;
    &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"border: none"&lt;/span&gt;
    &lt;span class="na"&gt;project_id=&lt;/span&gt;&lt;span class="s"&gt;"{PUBLIC_CORBADO_PROJECT_ID}"&lt;/span&gt;
    &lt;span class="na"&gt;conditional=&lt;/span&gt;&lt;span class="s"&gt;"yes"&lt;/span&gt;
    &lt;span class="na"&gt;login_title=&lt;/span&gt;&lt;span class="s"&gt;"Try passkey login"&lt;/span&gt;
    &lt;span class="na"&gt;login_btn=&lt;/span&gt;&lt;span class="s"&gt;"Passkey login"&lt;/span&gt;
    &lt;span class="na"&gt;register_title=&lt;/span&gt;&lt;span class="s"&gt;"Try passkey signup"&lt;/span&gt;
    &lt;span class="na"&gt;register_btn=&lt;/span&gt;&lt;span class="s"&gt;"Passkey signup"&lt;/span&gt;
        &lt;span class="na"&gt;auto_detect_language=&lt;/span&gt;&lt;span class="s"&gt;"no"&lt;/span&gt;
        &lt;span class="na"&gt;fallback_language=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;
    &lt;span class="na"&gt;page=&lt;/span&gt;&lt;span class="s"&gt;"register"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"Corbado-username"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"webauthn"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Corbado-auth&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The web component has various utility attributes to customize it, like &lt;code&gt;login_title&lt;/code&gt;, or &lt;code&gt;login_btn&lt;/code&gt;. What's important for you to get it to work is the &lt;code&gt;project_id&lt;/code&gt; attribute, where we will pass in our &lt;code&gt;PUBLIC_CORBADO_PROJECT_ID&lt;/code&gt; from the environment. If you use an Editor like VSCode with the Svelte extension, it will automatically add this import to your &lt;code&gt;.svelte&lt;/code&gt; &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PUBLIC_CORBADO_PROJECT_ID&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$env/static/public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5.3 Setting up the redirect logic
&lt;/h3&gt;

&lt;p&gt;The Corbado web component works by &lt;em&gt;redirecting&lt;/em&gt; you to a page you specify once the user signs up or logs in. This redirect URL can be a server-side route, or a client route. In our case, it will be a SvelteKit server endpoint. To set up our Redirect URL, let's go into the &lt;a href="https://app.Corbado.com"&gt;Corbado Developer Panel&lt;/a&gt; and navigate to the URL tab in Settings &amp;gt; General and enter the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Redirect URL&lt;/code&gt;: Enter the URL your app should redirect to once signing up with the web component. In our case, it is the SvelteKit API route &lt;code&gt;http://localhost:5137/api/register&lt;/code&gt; .&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Application URL&lt;/code&gt;: Enter the URL your application runs on, in our case it is &lt;code&gt;localhost:5137&lt;/code&gt; locally.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Relying Party ID&lt;/code&gt;: Enter the Domain (no protocol, port or path) where passkeys should be bound to. In our case it is &lt;code&gt;localhost&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The Application URL is used for, among others, to correctly direct users to the web component again, when they have clicked on an email magic link.&lt;/p&gt;

&lt;p&gt;Let's now add our server route in SvelteKit. Under the &lt;code&gt;routes/&lt;/code&gt; folder, we will create the folders &lt;code&gt;api/register&lt;/code&gt; and create a file &lt;code&gt;api/register/+server.ts&lt;/code&gt; in it. This will contain our API route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CORBADO_API_SECRET&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$env/static/private&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PUBLIC_CORBADO_PROJECT_ID&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;$env/static/public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;RequestHandler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@sveltejs/kit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getClientAddress&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cookies&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Corbado&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;searchParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sessionToken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user-agent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;getClientAddress&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://api.Corbado.com/v1/sessions/verify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Basic &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;btoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PUBLIC_CORBADO_PROJECT_ID&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;CORBADO_API_SECRET&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Corbado&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sessionToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;clientInfo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Corbado&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userAgent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;remoteAddress&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Corbado&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remoteAddress&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid session token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jwt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;crypto&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;randomUUID&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;httpOnly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;sameSite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lax&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;secure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="c1"&gt;// 1 day&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;303&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="nx"&gt;satisfies&lt;/span&gt; &lt;span class="nx"&gt;RequestHandler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's digest this one by one. This &lt;code&gt;GET&lt;/code&gt; route will be automatically called by the Corbado API once a user clicks on register or login. We then need to verify that information with the Corbado API, and can then authenticate our user locally.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;Corbado&lt;/code&gt; constant, we save all the information that is relevant to verification, such as &lt;code&gt;sessionToken&lt;/code&gt;, and &lt;code&gt;clientinfo&lt;/code&gt; such as the &lt;code&gt;userAgent&lt;/code&gt; and the &lt;code&gt;remoteAddress&lt;/code&gt;. SvelteKit provides useful helpers we can pass to the route to get all this information.&lt;/p&gt;

&lt;p&gt;Once we have that information, we want to call the Corbado API's &lt;code&gt;sessionVerify&lt;/code&gt; endpoint. We use our project ID and our secret that we saved in our &lt;code&gt;.env&lt;/code&gt; before to authenticate with Basic authentication, and in the body, we pass the sessionToken, and the &lt;code&gt;clientinfo&lt;/code&gt; we have gathered.&lt;/p&gt;

&lt;p&gt;If our response fails, we will let our endpoint throw an error. If we successfully verified, we can now set a cookie using a new &lt;code&gt;jwt&lt;/code&gt; token, and redirect our client back to the root. Note that in production, you would probably use the user information returned to you by the response of the &lt;code&gt;sessionVerify&lt;/code&gt; call to create a user in your database, but for our purpose, we'll just create a cookie locally.&lt;/p&gt;

&lt;h3&gt;
  
  
  5.4 Using cookies to manage authentication state
&lt;/h3&gt;

&lt;p&gt;Now that we can press sign up on our web component and get a cookie back, we need to load that cookie into our client and use it to show sign in status. To do this, we can use SvelteKit's &lt;code&gt;load&lt;/code&gt; functions. In our &lt;code&gt;routes&lt;/code&gt; folder root, we can create a &lt;code&gt;+page.server.ts&lt;/code&gt; next to the existing &lt;code&gt;+page.server.ts&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PageServerLoad&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./$types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;load&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;cookies&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jwt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;jwt&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="nx"&gt;satisfies&lt;/span&gt; &lt;span class="nx"&gt;PageServerLoad&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this does is get the jwt cookie that we set in the redirect, and pass it down to all pages in the same level of &lt;code&gt;routes&lt;/code&gt; or below.&lt;/p&gt;

&lt;p&gt;Earlier, in our root &lt;code&gt;+page.svelte&lt;/code&gt;, you might have noticed that there was an additional variable in our script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PageData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This data is populated with whatever the &lt;code&gt;load&lt;/code&gt; function of our page returns, in this case the content of our jwt cookie. We want to pass this cookie down into our &lt;code&gt;PasskeyDemo&lt;/code&gt; section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;PasskeyDemo&lt;/span&gt; &lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In that section, we also need to declare the &lt;code&gt;data&lt;/code&gt; prop to receive it from the parent page. This should be in our script section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PageData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can use that to conditionally render our UI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!--- other code ---&amp;gt;&lt;/span&gt;
{#if data &lt;span class="err"&gt;&amp;amp;&amp;amp;&lt;/span&gt; data.jwt}
&lt;span class="nt"&gt;&amp;lt;Card&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-full"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Heading&lt;/span&gt; &lt;span class="na"&gt;tag=&lt;/span&gt;&lt;span class="s"&gt;"h4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;That’s it. You’re logged in.​&lt;span class="nt"&gt;&amp;lt;/Heading&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/api/logout"&lt;/span&gt; &lt;span class="na"&gt;pill&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"bg-primary text-white mt-32 mb-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Log out&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Card&amp;gt;&lt;/span&gt;
{:else}
&lt;span class="nt"&gt;&amp;lt;Card&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"w-full"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Corbado-auth&lt;/span&gt;
        &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"border: none"&lt;/span&gt;
        &lt;span class="na"&gt;project_id=&lt;/span&gt;&lt;span class="s"&gt;"{PUBLIC_CORBADO_PROJECT_ID}"&lt;/span&gt;
        &lt;span class="na"&gt;conditional=&lt;/span&gt;&lt;span class="s"&gt;"yes"&lt;/span&gt;
        &lt;span class="na"&gt;login_title=&lt;/span&gt;&lt;span class="s"&gt;"Try passkey login"&lt;/span&gt;
        &lt;span class="na"&gt;login_btn=&lt;/span&gt;&lt;span class="s"&gt;"Passkey login"&lt;/span&gt;
        &lt;span class="na"&gt;register_title=&lt;/span&gt;&lt;span class="s"&gt;"Try passkey signup"&lt;/span&gt;
        &lt;span class="na"&gt;register_btn=&lt;/span&gt;&lt;span class="s"&gt;"Passkey signup"&lt;/span&gt;
        &lt;span class="na"&gt;page=&lt;/span&gt;&lt;span class="s"&gt;"register"&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"Corbado-username"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt; &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"webauthn"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/Corbado-auth&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Card&amp;gt;&lt;/span&gt;
{/if}
&lt;span class="c"&gt;&amp;lt;!--- other code ---&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will render either our web component if we are not logged in, or a log out button if we are already logged in. The Logout button uses another action. We can create that action by simply creating a file &lt;code&gt;api/logout/+server.ts&lt;/code&gt; with the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@sveltejs/kit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;RequestHandler&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./$types&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GET&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;cookies&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;cookies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jwt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;expires&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nx"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;303&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="nx"&gt;satisfies&lt;/span&gt; &lt;span class="nx"&gt;RequestHandler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This action will get invoked when the button is pressed, and it will delete the jwt token from the browser and redirect back to the page root.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope this demo showed how easy it is to quickly add passwordless authentication using passkeys to your SvelteKit app by using Corbado, and utilizing all of SvelteKit's features to make our lives easier in the process.&lt;/p&gt;

</description>
      <category>passkeys</category>
      <category>svelte</category>
      <category>webdev</category>
      <category>security</category>
    </item>
  </channel>
</rss>
