├── src
├── routes
│ ├── logout
│ │ ├── +page.svelte
│ │ └── +page.ts
│ ├── +layout.ts
│ ├── +layout.svelte
│ ├── +page.svelte
│ ├── dashboard
│ │ ├── +layout.svelte
│ │ └── +page.svelte
│ ├── recovery
│ │ └── +page.svelte
│ ├── settings
│ │ └── +page.svelte
│ ├── registration
│ │ └── +page.svelte
│ ├── login
│ │ └── +page.svelte
│ └── verification
│ │ └── +page.svelte
├── lib
│ ├── config.ts
│ ├── stores
│ │ └── kratos
│ │ │ └── identity.ts
│ ├── http
│ │ └── index.ts
│ ├── components
│ │ └── kratos
│ │ │ ├── fieldset-hidden.svelte
│ │ │ ├── messages.svelte
│ │ │ ├── fieldset-submit.svelte
│ │ │ ├── form.svelte
│ │ │ ├── fieldset-email.svelte
│ │ │ ├── fieldset-text.svelte
│ │ │ ├── fieldset-password.svelte
│ │ │ ├── fieldsets.svelte
│ │ │ └── fieldset-password-toggle.svelte
│ └── kratos
│ │ ├── index.ts
│ │ └── types.ts
├── app.d.ts
└── app.html
├── .npmrc
├── static
└── favicon.png
├── .eslintignore
├── .prettierignore
├── .gitignore
├── vite.config.js
├── .prettierrc
├── svelte.config.js
├── tsconfig.json
├── .eslintrc.cjs
├── package.json
├── README.md
└── docs
├── my-kratos.yml
└── local-test.md
/src/routes/logout/+page.svelte:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | engine-strict=true
2 | resolution-mode=highest
3 |
--------------------------------------------------------------------------------
/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emrahcom/kratos-selfservice-svelte-node/HEAD/static/favicon.png
--------------------------------------------------------------------------------
/src/lib/config.ts:
--------------------------------------------------------------------------------
1 | export const KRATOS = "https://kratos.mydomain.corp";
2 | export const APP = "https://app.mydomain.corp";
3 |
--------------------------------------------------------------------------------
/src/lib/stores/kratos/identity.ts:
--------------------------------------------------------------------------------
1 | import { writable } from "svelte/store";
2 | import type { KratosIdentity } from "$lib/kratos/types";
3 |
4 | export default writable({} as KratosIdentity);
5 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
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 |
--------------------------------------------------------------------------------
/.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 | *~
12 | *.sw?
13 | *.log
14 | package-lock.json
15 | yarn.lock
16 |
--------------------------------------------------------------------------------
/src/lib/http/index.ts:
--------------------------------------------------------------------------------
1 | export async function get(url: string) {
2 | const res = await fetch(url, {
3 | credentials: "include",
4 | headers: {
5 | "Accept": "application/json",
6 | },
7 | mode: "cors",
8 | });
9 |
10 | return res;
11 | }
12 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { sveltekit } from "@sveltejs/kit/vite";
2 | import { defineConfig } from "vite";
3 |
4 | export default defineConfig({
5 | plugins: [sveltekit()],
6 | server: {
7 | hmr: {
8 | clientPort: 3000,
9 | },
10 | },
11 | });
12 |
--------------------------------------------------------------------------------
/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 Platform {}
9 | }
10 | }
11 |
12 | export {};
13 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }],
3 | "plugins": ["prettier-plugin-svelte"],
4 | "pluginSearchDirs": ["."],
5 | "printWidth": 80,
6 | "quoteProps": "preserve",
7 | "singleQuote": false,
8 | "tabWidth": 2,
9 | "trailingComma": "all",
10 | "useTabs": false
11 | }
12 |
--------------------------------------------------------------------------------
/src/app.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | %sveltekit.head%
8 |
9 |
10 | %sveltekit.body%
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/lib/components/kratos/fieldset-hidden.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/lib/components/kratos/messages.svelte:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 | {#if messages}
9 | {#each messages as msg}
10 | {msg.id} -
11 | {msg.type} -
12 | {msg.text}
13 | {/each}
14 | {/if}
15 |
--------------------------------------------------------------------------------
/src/routes/+layout.ts:
--------------------------------------------------------------------------------
1 | import { getIdentity } from "$lib/kratos";
2 | import identity from "$lib/stores/kratos/identity";
3 |
4 | // -----------------------------------------------------------------------------
5 | export async function load() {
6 | await getIdentity()
7 | .then((_identity) => {
8 | identity.set(_identity);
9 | })
10 | .catch(() => {
11 | //no identity
12 | });
13 | }
14 |
--------------------------------------------------------------------------------
/src/routes/logout/+page.ts:
--------------------------------------------------------------------------------
1 | import { browser } from "$app/environment";
2 | import { getLogoutDataModels } from "$lib/kratos";
3 |
4 | // -----------------------------------------------------------------------------
5 | export async function load() {
6 | if (!browser) return {};
7 |
8 | const dm = await getLogoutDataModels();
9 |
10 | if (dm.instanceOf === "KratosLogout") {
11 | window.location.replace(dm.logout_url);
12 | } else {
13 | window.location.replace("/");
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/svelte.config.js:
--------------------------------------------------------------------------------
1 | //import adapter from '@sveltejs/adapter-auto';
2 | import adapter from "@sveltejs/adapter-node";
3 | import { vitePreprocess } from "@sveltejs/kit/vite";
4 |
5 | /** @type {import('@sveltejs/kit').Config} */
6 | const config = {
7 | // Consult https://kit.svelte.dev/docs/integrations#preprocessors
8 | // for more information about preprocessors
9 | preprocess: vitePreprocess(),
10 |
11 | kit: {
12 | adapter: adapter(),
13 | },
14 | };
15 |
16 | export default config;
17 |
--------------------------------------------------------------------------------
/src/lib/components/kratos/fieldset-submit.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
17 |
--------------------------------------------------------------------------------
/src/routes/+layout.svelte:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/src/routes/+page.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 | welcome
12 |
13 | {#if !_identity.id}
14 | login
15 | {:else}
16 | Dashboard
17 | {/if}
18 |
19 |
--------------------------------------------------------------------------------
/src/routes/dashboard/+layout.svelte:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/lib/components/kratos/form.svelte:
--------------------------------------------------------------------------------
1 |
12 |
13 |
14 |
17 |
--------------------------------------------------------------------------------
/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 | }
13 | // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias
14 | //
15 | // If you want to overwrite includes/excludes, make sure to copy over the
16 | // relevant includes/excludes from the referenced tsconfig.json
17 | // TypeScript does not merge them in
18 | }
19 |
--------------------------------------------------------------------------------
/src/routes/dashboard/+page.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
20 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: [
4 | "eslint:recommended",
5 | "plugin:@typescript-eslint/recommended",
6 | "plugin:svelte/recommended",
7 | "prettier",
8 | ],
9 | parser: "@typescript-eslint/parser",
10 | plugins: ["@typescript-eslint"],
11 | parserOptions: {
12 | sourceType: "module",
13 | ecmaVersion: 2020,
14 | extraFileExtensions: [".svelte"],
15 | },
16 | env: {
17 | browser: true,
18 | es2017: true,
19 | node: true,
20 | },
21 | overrides: [
22 | {
23 | files: ["*.svelte"],
24 | parser: "svelte-eslint-parser",
25 | parserOptions: {
26 | parser: "@typescript-eslint/parser",
27 | },
28 | },
29 | ],
30 | };
31 |
--------------------------------------------------------------------------------
/src/lib/components/kratos/fieldset-email.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/lib/components/kratos/fieldset-text.svelte:
--------------------------------------------------------------------------------
1 |
13 |
14 |
15 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/src/lib/components/kratos/fieldset-password.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/lib/components/kratos/fieldsets.svelte:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 | {#each nodes as node}
14 | {#if node.attributes.type === "hidden"}
15 |
16 | {:else if node.attributes.type === "password"}
17 |
18 | {:else if node.attributes.type === "text"}
19 |
20 | {:else if node.attributes.type === "email"}
21 |
22 | {:else if node.attributes.type === "submit"}
23 |
24 | {:else}
25 | unknow type
26 | {/if}
27 | {/each}
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "kratos-svelte-ui",
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 --plugin-search-dir . --check . && eslint .",
12 | "format": "prettier --plugin-search-dir . --write ."
13 | },
14 | "devDependencies": {
15 | "@sveltejs/adapter-auto": "^2.0.0",
16 | "@sveltejs/adapter-node": "^1.3.1",
17 | "@sveltejs/kit": "^1.20.4",
18 | "@typescript-eslint/eslint-plugin": "^5.45.0",
19 | "@typescript-eslint/parser": "^5.45.0",
20 | "eslint": "^8.28.0",
21 | "eslint-config-prettier": "^8.5.0",
22 | "eslint-plugin-svelte": "^2.30.0",
23 | "prettier": "^2.8.0",
24 | "prettier-plugin-svelte": "^2.10.1",
25 | "svelte": "^4.0.5",
26 | "svelte-check": "^3.4.3",
27 | "tslib": "^2.4.1",
28 | "typescript": "^5.0.0",
29 | "vite": "^4.4.2"
30 | },
31 | "type": "module"
32 | }
33 |
--------------------------------------------------------------------------------
/src/routes/recovery/+page.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 | {#await pr then dm}
19 | {#if dm.instanceOf === "KratosForm"}
20 |
21 |
recovery
22 |
23 | {#if dm.ui.messages}
24 |
25 | {:else}
26 |
27 | {/if}
28 |
29 | {:else}
30 | Something went wrong
31 | {/if}
32 | {/await}
33 |
34 |
--------------------------------------------------------------------------------
/src/routes/settings/+page.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 | {#await pr then dm}
19 | {#if dm.instanceOf === "KratosForm"}
20 |
21 |
Settings
22 |
23 | {#if dm.ui.messages}
24 |
25 | {:else}
26 |
27 |
28 |
29 | {/if}
30 |
31 | {:else}
32 | Something went wrong
33 | {/if}
34 | {/await}
35 |
36 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # kratos-selfservice-svelte-node
2 |
3 | Self-service [Svelte](https://svelte.dev/) node for
4 | [Ory Kratos](https://github.com/ory/kratos). It has no style or decoration.
5 | Apply your custom style according to your application.
6 |
7 | ## Install
8 |
9 | - `git`, `nodejs` and `yarn` must be installed
10 | - a working `Ory Kratos` is needed
11 |
12 | ```bash
13 | git clone https://github.com/emrahcom/kratos-selfservice-svelte-node.git
14 |
15 | cd kratos-selfservice-svelte-node
16 | yarn install
17 | ```
18 |
19 | ## Config
20 |
21 | Change `src/lib/config.ts` according to your environment.
22 |
23 | ```javascript
24 | export const KRATOS = "https://kratos.mydomain.corp";
25 | export const APP = "https://app.mydomain.corp";
26 | ```
27 |
28 | ## Run (dev)
29 |
30 | ```bash
31 | yarn run dev --host --port 3000
32 | ```
33 |
34 | ## Run (prod)
35 |
36 | ```bash
37 | yarn run build
38 | node build/index.js
39 | ```
40 |
41 | ## Pages
42 |
43 | - Landing page
44 |
45 | `/`
46 |
47 | - Secure dashboard
48 |
49 | `/dashboard`
50 |
51 | - Registration
52 |
53 | `/registration`
54 |
55 | - Login
56 |
57 | `/login`
58 |
59 | - Settings
60 |
61 | `/settings`
62 |
63 | - Recovery
64 |
65 | `/recovery`
66 |
67 | - Verification
68 |
69 | `/verification`
70 |
71 | - Logout
72 |
73 | `/logout`
74 |
--------------------------------------------------------------------------------
/src/routes/registration/+page.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 | {#await pr then dm}
19 | {#if dm.instanceOf === "KratosForm"}
20 |
21 |
Registration
22 |
23 | {#if dm.ui.messages}
24 |
25 | {/if}
26 |
27 |
28 |
29 |
30 |
33 |
34 | {:else}
35 | Something went wrong
36 | {/if}
37 | {/await}
38 |
39 |
--------------------------------------------------------------------------------
/src/routes/login/+page.svelte:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 | {#await pr then dm}
19 | {#if dm.instanceOf === "KratosForm"}
20 |
21 |
Sign in
22 |
23 | {#if dm.ui.messages}
24 |
25 | {/if}
26 |
27 |
28 |
29 |
30 |
34 |
35 | {:else}
36 | Something went wrong
37 | {/if}
38 | {/await}
39 |
40 |
--------------------------------------------------------------------------------
/src/routes/verification/+page.svelte:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 | {#await pr then dm}
28 | {#if dm.instanceOf === "KratosForm"}
29 |
30 |
verification
31 |
32 | {#if dm.ui.messages}
33 |
34 | {:else}
35 |
36 | {/if}
37 |
38 | {:else}
39 | Something went wrong
40 | {/if}
41 | {/await}
42 |
43 |
--------------------------------------------------------------------------------
/docs/my-kratos.yml:
--------------------------------------------------------------------------------
1 | version: v0.13.0
2 |
3 | dsn: memory
4 |
5 | serve:
6 | public:
7 | base_url: https://kratos.mydomain.corp/
8 | cors:
9 | enabled: true
10 | allowed_origins:
11 | - https://app.mydomain.corp
12 | admin:
13 | base_url: http://kratos.mydomain.corp:4434/
14 |
15 | selfservice:
16 | default_browser_return_url: https://app.mydomain.corp/
17 | allowed_return_urls:
18 | - https://app.mydomain.corp
19 |
20 | methods:
21 | password:
22 | enabled: true
23 | totp:
24 | config:
25 | issuer: Kratos
26 | enabled: true
27 | lookup_secret:
28 | enabled: true
29 | link:
30 | enabled: true
31 | code:
32 | enabled: true
33 |
34 | flows:
35 | error:
36 | ui_url: https://app.mydomain.corp/error
37 |
38 | settings:
39 | ui_url: https://app.mydomain.corp/settings
40 | privileged_session_max_age: 15m
41 | required_aal: highest_available
42 |
43 | recovery:
44 | enabled: true
45 | ui_url: https://app.mydomain.corp/recovery
46 | use: code
47 |
48 | verification:
49 | enabled: true
50 | ui_url: https://app.mydomain.corp/verification
51 | use: code
52 | after:
53 | default_browser_return_url: https://app.mydomain.corp/
54 |
55 | logout:
56 | after:
57 | default_browser_return_url: https://app.mydomain.corp/login
58 |
59 | login:
60 | ui_url: https://app.mydomain.corp/login
61 | lifespan: 10m
62 |
63 | registration:
64 | lifespan: 10m
65 | ui_url: https://app.mydomain.corp/registration
66 | after:
67 | password:
68 | hooks:
69 | - hook: session
70 | - hook: show_verification_ui
71 |
72 | log:
73 | level: debug
74 | format: text
75 | leak_sensitive_values: true
76 |
77 | secrets:
78 | cookie:
79 | - PLEASE-CHANGE-ME-I-AM-VERY-INSECURE
80 | cipher:
81 | - 32-LONG-SECRET-NOT-SECURE-AT-ALL
82 |
83 | ciphers:
84 | algorithm: xchacha20-poly1305
85 |
86 | hashers:
87 | algorithm: bcrypt
88 | bcrypt:
89 | cost: 8
90 |
91 | identity:
92 | default_schema_id: default
93 | schemas:
94 | - id: default
95 | url: file:///etc/config/kratos/identity.schema.json
96 |
97 | courier:
98 | smtp:
99 | connection_uri: smtps://test:test@mailslurper:1025/?skip_ssl_verify=true
100 |
--------------------------------------------------------------------------------
/docs/local-test.md:
--------------------------------------------------------------------------------
1 | # Local Test Environment
2 |
3 | ## Kratos
4 |
5 | ```bash
6 | git clone https://github.com/ory/kratos.git
7 | cd kratos
8 | git checkout v1.0.0
9 | ```
10 |
11 | Update `./contrib/quickstart/kratos/email-password/kratos.yml` according to
12 | `my-kratos.yml` in this folder.
13 |
14 | ```bash
15 | docker-compose -f quickstart.yml up --build --force-recreate
16 | ```
17 |
18 | ## App
19 |
20 | ```bash
21 | cd kratos-selfservice-svelte-node
22 | yarn run dev --host --port 3000
23 | ```
24 |
25 | ## Nginx
26 |
27 | `/etc/nginx/sites-available/kratos.conf`
28 |
29 | ```conf
30 | # ------------------------------------------------------------------------------
31 | # kratos.mydomain.corp
32 | # ------------------------------------------------------------------------------
33 | server {
34 | listen 443 ssl;
35 | listen [::]:443 ssl;
36 |
37 | include snippets/snakeoil.conf;
38 | server_name kratos.mydomain.corp;
39 |
40 | location / {
41 | proxy_pass http://172.18.18.1:4433;
42 | proxy_http_version 1.1;
43 | proxy_set_header Host $http_host;
44 | proxy_set_header X-Real-IP $remote_addr;
45 | proxy_set_header X-Forwarded-For $remote_addr;
46 | tcp_nodelay on;
47 | }
48 | }
49 |
50 | # ------------------------------------------------------------------------------
51 | # app.mydomain.corp
52 | # ------------------------------------------------------------------------------
53 | server {
54 | listen 443 ssl;
55 | listen [::]:443 ssl;
56 |
57 | include snippets/snakeoil.conf;
58 | server_name app.mydomain.corp;
59 |
60 | location / {
61 | proxy_pass http://172.18.18.1:3000;
62 | proxy_http_version 1.1;
63 | proxy_set_header Host $http_host;
64 | proxy_set_header X-Real-IP $remote_addr;
65 | proxy_set_header X-Forwarded-For $remote_addr;
66 | tcp_nodelay on;
67 | }
68 | }
69 |
70 | server {
71 | listen 3000 ssl;
72 | listen [::]:3000 ssl;
73 |
74 | include snippets/snakeoil.conf;
75 | server_name app.mydomain.corp;
76 |
77 | location / {
78 | proxy_pass http://172.18.18.1:3000;
79 | proxy_http_version 1.1;
80 | proxy_set_header Host $http_host;
81 | proxy_set_header X-Real-IP $remote_addr;
82 | proxy_set_header X-Forwarded-For $remote_addr;
83 | proxy_set_header Upgrade $http_upgrade;
84 | proxy_set_header Connection "upgrade";
85 | tcp_nodelay on;
86 | }
87 | }
88 | ```
89 |
90 | ```bash
91 | ln -s ../sites-available/kratos.conf /etc/nginx/sites-enabled/
92 | systemctl restart nginx
93 | ```
94 |
--------------------------------------------------------------------------------
/src/lib/kratos/index.ts:
--------------------------------------------------------------------------------
1 | import { browser } from "$app/environment";
2 | import { KRATOS } from "$lib/config";
3 | import { get } from "$lib/http";
4 | import type {
5 | KratosError,
6 | KratosForm,
7 | KratosIdentity,
8 | KratosLogout,
9 | } from "$lib/kratos/types";
10 |
11 | // -----------------------------------------------------------------------------
12 | export function getFlowId(urlSearch: string): string {
13 | const qs = new URLSearchParams(urlSearch);
14 | const flowId = qs.get("flow");
15 |
16 | if (flowId) return flowId;
17 |
18 | return "";
19 | }
20 |
21 | // -----------------------------------------------------------------------------
22 | export async function getIdentity(): Promise {
23 | if (!browser) throw new Error("no browser environment");
24 |
25 | const url = `${KRATOS}/sessions/whoami`;
26 | const res = await get(url);
27 |
28 | if (res.status !== 200) {
29 | throw new Error("no identity");
30 | }
31 |
32 | const dm = await res.json();
33 | return dm.identity;
34 | }
35 |
36 | // -----------------------------------------------------------------------------
37 | export async function getDataModels(
38 | flow: string,
39 | flowId: string,
40 | ): Promise {
41 | if (!flowId) throw new Error("no flowId");
42 | if (!browser) throw new Error("no browser environment");
43 |
44 | const url = `${KRATOS}/self-service/${flow}/flows?id=${flowId}`;
45 | const res = await get(url);
46 | const dm = await res.json();
47 |
48 | if (dm.error) {
49 | dm.instanceOf = "KratosError";
50 |
51 | if (dm.error.details && dm.error.details.redirect_to) {
52 | window.location.href = dm.error.details.redirect_to;
53 | }
54 | } else if (dm.ui) {
55 | dm.instanceOf = "KratosForm";
56 | } else {
57 | throw new Error("unexpected Kratos object");
58 | }
59 |
60 | return dm;
61 | }
62 |
63 | // -----------------------------------------------------------------------------
64 | export async function getLogoutDataModels(): Promise<
65 | KratosLogout | KratosError
66 | > {
67 | if (!browser) throw new Error("no browser environment");
68 |
69 | const url = `${KRATOS}/self-service/logout/browser`;
70 | const res = await get(url);
71 | const dm = await res.json();
72 |
73 | if (dm.error) {
74 | dm.instanceOf = "KratosError";
75 | } else if (dm.logout_url) {
76 | dm.instanceOf = "KratosLogout";
77 | } else {
78 | throw new Error("unexpected Kratos object");
79 | }
80 |
81 | return dm;
82 | }
83 |
--------------------------------------------------------------------------------
/src/lib/components/kratos/fieldset-password-toggle.svelte:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
83 |
--------------------------------------------------------------------------------
/src/lib/kratos/types.ts:
--------------------------------------------------------------------------------
1 | // -----------------------------------------------------------------------------
2 | export interface Attributes {
3 | name: string;
4 | type: string;
5 | value?: string;
6 | disabled: boolean;
7 | required?: boolean;
8 | }
9 |
10 | // -----------------------------------------------------------------------------
11 | export interface Label {
12 | id: number;
13 | type: string;
14 | text: string;
15 | context?: unknown;
16 | }
17 |
18 | // -----------------------------------------------------------------------------
19 | export interface Message {
20 | id: number;
21 | type: string;
22 | text: string;
23 | context?: unknown;
24 | }
25 |
26 | // -----------------------------------------------------------------------------
27 | export interface Meta {
28 | label?: Label;
29 | }
30 |
31 | // -----------------------------------------------------------------------------
32 | export interface Node {
33 | type: string;
34 | group: string;
35 | attributes: Attributes;
36 | messages: Message[];
37 | meta: Meta;
38 | }
39 |
40 | // -----------------------------------------------------------------------------
41 | export interface UI {
42 | action: string;
43 | method: string;
44 | messages?: Message[];
45 | nodes: Node[];
46 | "updated_at": string;
47 | }
48 |
49 | // -----------------------------------------------------------------------------
50 | export interface KratosForm {
51 | instanceOf: "KratosForm";
52 | id: string;
53 | type: string;
54 | forced?: boolean;
55 | ui: UI;
56 | "created_at"?: string;
57 | "expires_at": string;
58 | "issued_at": string;
59 | "updated_at"?: string;
60 | "request_url": string;
61 | }
62 |
63 | // -----------------------------------------------------------------------------
64 | export interface KratosError {
65 | instanceOf: "KratosError";
66 | error: {
67 | code: number;
68 | message: string;
69 | status: string;
70 | reason?: string;
71 | details?: {
72 | docs: string;
73 | hint: string;
74 | "redirect_to": string;
75 | "reject_reason": string;
76 | };
77 | };
78 | }
79 |
80 | // -----------------------------------------------------------------------------
81 | export interface KratosLogout {
82 | instanceOf: "KratosLogout";
83 | "logout_url": string;
84 | }
85 |
86 | // -----------------------------------------------------------------------------
87 | export interface KratosIdentity {
88 | id: string;
89 | traits: {
90 | email: string;
91 | };
92 | state: string;
93 | "created_at": string;
94 | "updated_at": string;
95 | }
96 |
97 | // -----------------------------------------------------------------------------
98 | export interface KratosLoad {
99 | status?: number;
100 | redirect?: string;
101 | props?: {
102 | [key: string]:
103 | | string
104 | | KratosError
105 | | KratosForm
106 | | KratosIdentity
107 | | KratosLogout;
108 | };
109 | }
110 |
--------------------------------------------------------------------------------