├── .npmrc ├── src ├── routes │ ├── +layout.server.ts │ ├── +page.svelte │ ├── +layout.svelte │ └── profile │ │ ├── +page.svelte │ │ └── +page.server.ts ├── lib │ └── index.ts ├── app.d.ts └── app.html ├── static └── favicon.png ├── .prettierignore ├── vite.config.ts ├── .env.example ├── .gitignore ├── .eslintignore ├── .prettierrc ├── tsconfig.json ├── .eslintrc.cjs ├── svelte.config.js ├── package.json └── README.md /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /src/routes/+layout.server.ts: -------------------------------------------------------------------------------- 1 | export const ssr = false; 2 | -------------------------------------------------------------------------------- /src/lib/index.ts: -------------------------------------------------------------------------------- 1 | // place files you want to import through the `$lib` alias in this folder. 2 | -------------------------------------------------------------------------------- /static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/corbado/example-passkeys-sveltekit/HEAD/static/favicon.png -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Ignore files for PNPM, NPM and YARN 2 | pnpm-lock.yaml 3 | package-lock.json 4 | yarn.lock 5 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import { defineConfig } from 'vite'; 3 | 4 | export default defineConfig({ 5 | plugins: [sveltekit()] 6 | }); 7 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | PUBLIC_CORBADO_PROJECT_ID= 2 | CORBADO_API_SECRET= 3 | CORBADO_FRONTEND_API= 4 | CORBADO_BACKEND_API= -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | vite.config.js.timestamp-* 10 | vite.config.ts.timestamp-* 11 | .idea -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | 10 | # Ignore files for PNPM, NPM and YARN 11 | pnpm-lock.yaml 12 | package-lock.json 13 | yarn.lock 14 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": false, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100, 6 | "plugins": ["prettier-plugin-svelte"], 7 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }], 8 | "tabWidth": 4 9 | } 10 | -------------------------------------------------------------------------------- /src/app.d.ts: -------------------------------------------------------------------------------- 1 | // See https://kit.svelte.dev/docs/types#app 2 | // for information about these interfaces 3 | declare global { 4 | namespace App { 5 | // interface Error {} 6 | // interface Locals {} 7 | // interface PageData {} 8 | // interface PageState {} 9 | // interface Platform {} 10 | } 11 | } 12 | 13 | export {}; 14 | -------------------------------------------------------------------------------- /src/app.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | %sveltekit.head% 8 | 9 | 10 |
%sveltekit.body%
11 | 12 | 13 | -------------------------------------------------------------------------------- /src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 15 | 16 |
-------------------------------------------------------------------------------- /src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 16 | 17 |
18 | {#if isInitialized} 19 | 20 | {/if} 21 |
-------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./.svelte-kit/tsconfig.json", 3 | "compilerOptions": { 4 | "allowJs": true, 5 | "checkJs": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "resolveJsonModule": true, 9 | "skipLibCheck": true, 10 | "sourceMap": true, 11 | "strict": true, 12 | "moduleResolution": "bundler" 13 | } 14 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias 15 | // except $lib which is handled by https://kit.svelte.dev/docs/configuration#files 16 | // 17 | // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes 18 | // from the referenced tsconfig.json - TypeScript does not merge them in 19 | } 20 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /** @type { import("eslint").Linter.Config } */ 2 | module.exports = { 3 | root: true, 4 | extends: [ 5 | 'eslint:recommended', 6 | 'plugin:@typescript-eslint/recommended', 7 | 'plugin:svelte/recommended', 8 | 'prettier' 9 | ], 10 | parser: '@typescript-eslint/parser', 11 | plugins: ['@typescript-eslint'], 12 | parserOptions: { 13 | sourceType: 'module', 14 | ecmaVersion: 2020, 15 | extraFileExtensions: ['.svelte'] 16 | }, 17 | env: { 18 | browser: true, 19 | es2017: true, 20 | node: true 21 | }, 22 | overrides: [ 23 | { 24 | files: ['*.svelte'], 25 | parser: 'svelte-eslint-parser', 26 | parserOptions: { 27 | parser: '@typescript-eslint/parser' 28 | } 29 | } 30 | ] 31 | }; 32 | -------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-auto'; 2 | import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors 7 | // for more information about preprocessors 8 | preprocess: vitePreprocess(), 9 | 10 | kit: { 11 | // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. 12 | // If your environment is not supported, or you settled on a specific environment, switch out the adapter. 13 | // See https://kit.svelte.dev/docs/adapters for more information about adapters. 14 | adapter: adapter() 15 | } 16 | }; 17 | 18 | export default config; 19 | -------------------------------------------------------------------------------- /src/routes/profile/+page.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
15 | {#if (data.user)} 16 |

17 | Profile Page 18 |

19 |

20 | User-ID: {data.user.userId} 21 |

22 |

23 | Full name: {data.user.fullName} 24 |

25 | 28 | {:else} 29 |

30 | You aren't logged in. 31 |

32 |

Go Home

33 | {/if} 34 |
-------------------------------------------------------------------------------- /src/routes/profile/+page.server.ts: -------------------------------------------------------------------------------- 1 | import { type RequestEvent } from '@sveltejs/kit'; 2 | import { PUBLIC_CORBADO_PROJECT_ID } from '$env/static/public'; 3 | import { CORBADO_API_SECRET } from '$env/static/private'; 4 | import { CORBADO_FRONTEND_API } from '$env/static/private'; 5 | import { CORBADO_BACKEND_API } from '$env/static/private'; 6 | import { SDK, Config } from '@corbado/node-sdk'; 7 | 8 | const config = new Config(PUBLIC_CORBADO_PROJECT_ID, CORBADO_API_SECRET, CORBADO_FRONTEND_API, CORBADO_BACKEND_API); 9 | const sdk = new SDK(config); 10 | 11 | export async function load({ cookies }: RequestEvent) { 12 | const sessionToken = cookies.get("cbo_session_token"); 13 | if (!sessionToken) { 14 | return {user: undefined} 15 | } 16 | 17 | try { 18 | const user = await sdk.sessions().validateToken(sessionToken); 19 | 20 | return { user: { userId: user.userId, fullName: user.fullName } }; 21 | } catch { 22 | // session token was invalid 23 | return {user: undefined} 24 | } 25 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example-passkeys-svelte", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vite dev", 7 | "build": "vite build", 8 | "preview": "vite preview", 9 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 10 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 11 | "lint": "prettier --check . && eslint .", 12 | "format": "prettier --write ." 13 | }, 14 | "devDependencies": { 15 | "@corbado/types": "^2.3.3-alpha.0", 16 | "@sveltejs/adapter-auto": "^3.0.0", 17 | "@sveltejs/kit": "^2.0.0", 18 | "@sveltejs/vite-plugin-svelte": "^3.0.0", 19 | "@types/eslint": "^8.56.0", 20 | "@typescript-eslint/eslint-plugin": "^7.0.0", 21 | "@typescript-eslint/parser": "^7.0.0", 22 | "eslint": "^8.56.0", 23 | "eslint-config-prettier": "^9.1.0", 24 | "eslint-plugin-svelte": "^2.35.1", 25 | "prettier": "^3.1.1", 26 | "prettier-plugin-svelte": "^3.1.2", 27 | "svelte": "^4.2.7", 28 | "svelte-check": "^3.6.0", 29 | "tslib": "^2.4.1", 30 | "typescript": "^5.0.0", 31 | "vite": "^5.0.3" 32 | }, 33 | "type": "module", 34 | "dependencies": { 35 | "@corbado/node-sdk": "^3.0.2", 36 | "@corbado/web-js": "^2.18.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Svelte Passkey Example App 2 | 3 | This is a sample implementation of the Corbado UI component and Node SDK being integrated into a web application built 4 | with Sveltekit. 5 | 6 | Please see the [full blog post](https://www.corbado.com/blog/sveltekit-passkeys) to understand the detailed steps needed to 7 | integrate passkeys into Svelte apps. 8 | 9 | ## File structure 10 | 11 | - `src/routes/+page.svelte`: component for the sign up / login screen 12 | - `src/routes/profile/+page.server.ts`: Used to load user information on the server side 13 | - `src/routes/profile/+page.svelte`: component for the user profile information that is shown after successful 14 | authentication 15 | - `src/routes/+layout.server.ts`: file to switch SSR off (we're working on SSR support already) 16 | - `.env`: add Corbado project ID and project secret as environment variables that you can obtain 17 | from the [Corbado developer panel](https://app.corbado.com/signin#register) 18 | 19 | ## Setup 20 | 21 | ### Prerequisites 22 | 23 | Please follow the steps in [Getting started](https://docs.corbado.com/overview/getting-started) to create and configure 24 | a project in the [Corbado developer panel](https://app.corbado.com/signin#register). 25 | 26 | You need to have [Node](https://nodejs.org/en/download) and `npm` installed to run it. 27 | 28 | ## Usage 29 | 30 | Run 31 | 32 | ```bash 33 | npm i 34 | ``` 35 | 36 | to install all dependencies. 37 | 38 | Finally, you can run the project locally with 39 | 40 | ```bash 41 | npm run dev 42 | ``` 43 | --------------------------------------------------------------------------------