├── .eslintignore ├── .eslintrc.cjs ├── .github ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── FUNDING.yaml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .npmrc ├── .prettierignore ├── .prettierrc ├── README.md ├── package-lock.json ├── package.json ├── playwright.config.ts ├── src ├── app.d.ts ├── app.html ├── lib │ ├── components │ │ ├── AuthorizerBasicAuthLogin.svelte │ │ ├── AuthorizerForgotPassword.svelte │ │ ├── AuthorizerMagicLinkLogin.svelte │ │ ├── AuthorizerProvider.svelte │ │ ├── AuthorizerResetPassword.svelte │ │ ├── AuthorizerRoot.svelte │ │ ├── AuthorizerSignup.svelte │ │ ├── AuthorizerSocialLogin.svelte │ │ ├── AuthorizerVerifyOtp.svelte │ │ ├── Message.svelte │ │ └── PasswordStrengthIndicator.svelte │ ├── constants │ │ └── index.ts │ ├── icons │ │ ├── Apple.svelte │ │ ├── Close.svelte │ │ ├── Facebook.svelte │ │ ├── Github.svelte │ │ ├── Google.svelte │ │ ├── Linkedin.svelte │ │ ├── Microsoft.svelte │ │ ├── Twitter.svelte │ │ └── index.ts │ ├── index.ts │ ├── store │ │ └── index.ts │ ├── styledComponents │ │ ├── StyledButton.svelte │ │ ├── StyledFlex.svelte │ │ ├── StyledFooter.svelte │ │ ├── StyledFormGroup.svelte │ │ ├── StyledLink.svelte │ │ ├── StyledMessageWrapper.svelte │ │ ├── StyledPasswordStrength.svelte │ │ ├── StyledPasswordStrengthWrapper.svelte │ │ ├── StyledSeparator.svelte │ │ ├── StyledWrapper.svelte │ │ └── index.ts │ ├── styles │ │ └── default.css │ ├── types │ │ └── index.ts │ └── utils │ │ ├── common.ts │ │ ├── url.ts │ │ └── window.ts └── routes │ ├── +layout.svelte │ ├── +page.svelte │ └── reset-password │ └── +page.svelte ├── static └── favicon.png ├── svelte.config.js ├── tsconfig.json └── vite.config.ts /.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 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: '@typescript-eslint/parser', 4 | extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'], 5 | plugins: ['svelte3', '@typescript-eslint'], 6 | ignorePatterns: ['*.cjs'], 7 | overrides: [{ files: ['*.svelte'], processor: 'svelte3/svelte3' }], 8 | settings: { 9 | 'svelte3/typescript': () => require('typescript') 10 | }, 11 | parserOptions: { 12 | sourceType: 'module', 13 | ecmaVersion: 2020 14 | }, 15 | env: { 16 | browser: true, 17 | es2017: true, 18 | node: true 19 | } 20 | }; 21 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We're so excited you're interested in helping with Authorizer! We are happy to help you get started, even if you don't have any previous open-source experience :blush: 4 | 5 | ## New to Open Source? 6 | 7 | 1. Take a look at [How to Contribute to an Open Source Project on GitHub](https://egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github) 8 | 2. Go through the [Authorizer Code of Conduct](https://github.com/authorizerdev/authorizer-svelete/blob/main/.github/CODE_OF_CONDUCT.md) 9 | 10 | ## Where to ask questions? 11 | 12 | 1. Check our [Github Issues](https://github.com/authorizerdev/authorizer/issues) to see if someone has already answered your question. 13 | 2. Join our community on [Discord](https://discord.gg/Zv2D5h6kkK) and feel free to ask us your questions 14 | 15 | As you gain experience with Authorizer, please help answer other people's questions! :pray: 16 | 17 | ## What to work on? 18 | 19 | You can get started by taking a look at our [Github issues](https://github.com/authorizerdev/authorizer-svelte/issues) 20 | If you find one that looks interesting and no one else is already working on it, comment on that issue and start contributing 🙂. 21 | 22 | Please ask as many questions as you need, either directly in the issue or on [Discord](https://discord.gg/Zv2D5h6kkK). We're happy to help!:raised_hands: 23 | 24 | ### Contributions that are ALWAYS welcome 25 | 26 | 1. More tests 27 | 2. Improved Docs 28 | 3. Improved error messages 29 | 4. Educational content like blogs, videos, courses 30 | 31 | ## Development Setup 32 | 33 | ### Prerequisites 34 | 35 | - OS: Linux or macOS or windows 36 | - NodeJS: >= v16.17.1 37 | 38 | ### Familiarize yourself with Authorizer 39 | 40 | 1. [Architecture of Authorizer](http://docs.authorizer.dev/) 41 | 2. [GraphQL APIs](https://docs.authorizer.dev/core/graphql-api/) 42 | 3. [authorizer-js](https://docs.authorizer.dev/authorizer-js). authorizer-js is used under the hood to make requests to authorizer server. 43 | 44 | ### Project Setup for Authorizer svelte 45 | 46 | 1. Fork the [authorizer](https://github.com/authorizerdev/authorizer-svelte) repository (**Skip this step if you have access to repo**) 47 | 2. Clone repo: `git clone https://github.com/authorizerdev/authorizer-svelte.git` or use the forked url from step 1 48 | 3. Change directory to authorizer: `cd authorizer-svelte` 49 | 4. Install dependencies `npm install` or `yarn` 50 | 5. Update authorizer URL in `src/routes/+layout.svelte` if you are not using local instance of authorizer. 51 | 6. Make necessary changes in `src/lib` 52 | 7. Run in development mode `npm run dev` or `yarn dev` 53 | -------------------------------------------------------------------------------- /.github/FUNDING.yaml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: authorizerdev 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | --- 8 | 9 | **Version:** x.y.z 10 | 11 | 12 | 13 | **Describe the bug** 14 | 15 | 16 | 17 | **Steps To Reproduce** 18 | 19 | 20 | 21 | **Expected behavior** 22 | 23 | 24 | 25 | **Screenshots** 26 | 27 | 28 | 29 | **Desktop (please complete the following information):** 30 | 31 | - OS: [e.g. iOS] 32 | - Browser [e.g. chrome, safari] 33 | - Version [e.g. 22] 34 | 35 | **Additional context** 36 | 37 | 38 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea or enhancement for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: '' 7 | --- 8 | 9 | **Feature Description** 10 | 11 | 12 | 13 | **Describe the solution you'd like** 14 | 15 | 16 | 17 | **Describe alternatives you've considered** 18 | 19 | 20 | 21 | **Additional context** 22 | 23 | 24 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | #### What does this PR do? 2 | 3 | #### Which issue(s) does this PR fix? 4 | 5 | #### If this PR affects any API reference documentation, please share the updated endpoint references 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /build 4 | /.svelte-kit 5 | /package 6 | .env 7 | .env.* 8 | !.env.example 9 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | engine-strict=true 2 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "useTabs": true, 3 | "singleQuote": true, 4 | "trailingComma": "none", 5 | "printWidth": 100, 6 | "plugins": ["prettier-plugin-svelte"], 7 | "pluginSearchDirs": ["."], 8 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] 9 | } 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # authorizer-svelte 2 | 3 | Svelte SDK for [authorizer.dev](https://authorizer.dev) integration in your [svelte-js](https://svelte.dev/) application. This will allow you to have authentication and authorization ready in minutes. 4 | 5 | For detailed information about all the components check [docs](https://docs.authorizer.dev/authorizer-svelte) 6 | 7 | ## Getting Started 8 | 9 | Here is a quick guide on getting started with `@authorizerdev/authorizer-svelte` package. 10 | 11 | ### Step 1 - Create Instance 12 | 13 | Get Authorizer URL by instantiating [Authorizer instance](/deployment) and configuring it with necessary [environment variables](/core/env). 14 | 15 | ### Step 2 - Install package 16 | 17 | Assuming you have svelte-js application up and running, install following package in your application 18 | 19 | ```sh 20 | npm i --save @authorizerdev/authorizer-svelte 21 | OR 22 | yarn add @authorizerdev/authorizer-svelte 23 | ``` 24 | 25 | ### Step 3 - Configure Provider and use Authorizer Component 26 | 27 | Authorizer comes with global context `authorizerContext` which is available once you have configured `AuthorizerProvider` component. 28 | 29 | Configure `AuthorizerProvider` at root level in your application and import `default.css`. 30 | 31 | > Note: You can override default style with `css` variables. Check [docs](https://docs.authorizer.dev/authorizer-svelte) for more details. 32 | 33 | `eg: routes/+layout.svelte` 34 | 35 | ```svelte 36 | 40 | 41 | 48 | 49 | 50 | ``` 51 | 52 | **Use `Authorizer` Component** 53 | 54 | `eg: routes/+page.svelte` 55 | 56 | ```svelte 57 | 76 | 77 | {#if state.user} 78 |
79 |

Hey 👋,

80 | {state.user.email} 81 |
82 | {#if state.loading} 83 |

Processing....

84 | {:else} 85 |

Logout

86 | {/if} 87 |
88 | {:else} 89 |
90 |

Welcome to Authorizer

91 |
92 | 93 |
94 | {/if} 95 | ``` 96 | 97 | ## Support our work 98 | 99 | Github Sponsorship: https://github.com/sponsors/authorizerdev 100 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@authorizerdev/authorizer-svelte", 3 | "version": "0.1.9", 4 | "license": "MIT", 5 | "author": "Lakhan Samani", 6 | "scripts": { 7 | "dev": "vite dev", 8 | "build": "svelte-kit sync && svelte-package", 9 | "test": "playwright test", 10 | "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", 11 | "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", 12 | "lint": "prettier --plugin-search-dir . --check . && eslint .", 13 | "format": "prettier --plugin-search-dir . --write ." 14 | }, 15 | "devDependencies": { 16 | "@playwright/test": "^1.25.0", 17 | "@sveltejs/adapter-auto": "next", 18 | "@sveltejs/kit": "next", 19 | "@sveltejs/package": "next", 20 | "@typescript-eslint/eslint-plugin": "^5.27.0", 21 | "@typescript-eslint/parser": "^5.27.0", 22 | "eslint": "^8.16.0", 23 | "eslint-config-prettier": "^8.3.0", 24 | "eslint-plugin-svelte3": "^4.0.0", 25 | "prettier": "^2.6.2", 26 | "prettier-plugin-svelte": "^2.7.0", 27 | "svelte": "^3.44.0", 28 | "svelte-check": "^2.7.1", 29 | "svelte-preprocess": "^4.10.6", 30 | "tslib": "^2.3.1", 31 | "typescript": "^4.7.4", 32 | "vite": "^3.1.0" 33 | }, 34 | "type": "module", 35 | "dependencies": { 36 | "@authorizerdev/authorizer-js": "^1.2.6" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /playwright.config.ts: -------------------------------------------------------------------------------- 1 | import type { PlaywrightTestConfig } from '@playwright/test'; 2 | 3 | const config: PlaywrightTestConfig = { 4 | webServer: { 5 | command: 'npm run build && npm run preview', 6 | port: 4173 7 | } 8 | }; 9 | 10 | export default config; 11 | -------------------------------------------------------------------------------- /src/app.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | // See https://kit.svelte.dev/docs/types#app 4 | // for information about these interfaces 5 | // and what to do when importing types 6 | declare namespace App { 7 | // interface Locals {} 8 | // interface PageData {} 9 | // interface Error {} 10 | // interface Platform {} 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/AuthorizerBasicAuthLogin.svelte: -------------------------------------------------------------------------------- 1 | 106 | 107 | {#if otpData.isScreenVisible && otpData.email} 108 | 109 | {:else} 110 |
111 | {#if componentState.error} 112 | 113 | {/if} 114 |
115 | 116 | 120 | 128 |
129 | {errorData.email} 130 |
131 |
132 | 133 | 137 | 145 |
146 | {errorData.password} 147 |
148 |
149 |
150 | 158 | {#if componentState.loading} 159 | Processing ... 160 | {:else} 161 | Log In 162 | {/if} 163 | 164 |
165 | {#if setView} 166 | 167 | setView && setView(Views.ForgotPassword)} marginBottom={'10px'}> 168 | Forgot Password? 169 | 170 | {#if state.config.is_sign_up_enabled} 171 |
172 | Don't have an account? 173 | setView && setView(Views.Signup)}>Sign Up 174 |
175 | {/if} 176 |
177 | {/if} 178 |
179 | {/if} 180 | 181 | 182 | -------------------------------------------------------------------------------- /src/lib/components/AuthorizerForgotPassword.svelte: -------------------------------------------------------------------------------- 1 | 65 | 66 | {#if componentState.successMessage} 67 | 68 | {:else} 69 | {#if componentState.error} 70 | 71 | {/if} 72 |

73 | Please enter your email address. 74 |
75 | We will send you an email to reset your password. 76 |

77 |
78 |
79 | 80 | 84 | 92 |
93 | {emailError} 94 |
95 |
96 |
97 | 101 | {#if componentState.loading} 102 | Processing ... 103 | {:else} 104 | Send Email 105 | {/if} 106 | 107 |
108 | {#if setView} 109 | 110 |
111 | Remember your password? 112 | setView && setView(Views.Login)}>Log In 113 |
114 |
115 | {/if} 116 | {/if} 117 | -------------------------------------------------------------------------------- /src/lib/components/AuthorizerMagicLinkLogin.svelte: -------------------------------------------------------------------------------- 1 | 78 | 79 | {#if componentState.successMessage} 80 | 81 | {:else} 82 | {#if componentState.error} 83 | 84 | {/if} 85 |
86 | 87 | 91 | 99 |
100 | {emailError} 101 |
102 |
103 |
104 | 108 | {#if componentState.loading} 109 | Processing ... 110 | {:else} 111 | Send Email 112 | {/if} 113 | 114 |
115 | {/if} 116 | -------------------------------------------------------------------------------- /src/lib/components/AuthorizerProvider.svelte: -------------------------------------------------------------------------------- 1 | 211 | 212 | Authorizer Provider Component 213 | -------------------------------------------------------------------------------- /src/lib/components/AuthorizerResetPassword.svelte: -------------------------------------------------------------------------------- 1 | 81 | 82 | 83 | {#if componentState.error} 84 | 85 | {/if} 86 |
87 | 88 | 92 | 100 |
101 | {errorData.password} 102 |
103 |
104 | 105 | 109 | 119 |
120 | {errorData.confirmPassword} 121 |
122 |
123 | {#if state.config.is_strong_password_enabled} 124 | 125 |
126 | {/if} 127 | 136 | {#if componentState.loading} 137 | Processing ... 138 | {:else} 139 | Continue 140 | {/if} 141 | 142 | 143 |
144 | -------------------------------------------------------------------------------- /src/lib/components/AuthorizerRoot.svelte: -------------------------------------------------------------------------------- 1 | 58 | 59 | 60 | 61 | {#if view === Views.Login && state.config.is_basic_authentication_enabled && !state.config.is_magic_link_login_enabled} 62 | 63 | {/if} 64 | {#if view === Views.Signup && state.config.is_basic_authentication_enabled && !state.config.is_magic_link_login_enabled && state.config.is_sign_up_enabled} 65 | 66 | {/if} 67 | {#if view === Views.Login && state.config.is_magic_link_login_enabled} 68 | 69 | {/if} 70 | {#if view === Views.ForgotPassword} 71 | 72 | {/if} 73 | 74 | -------------------------------------------------------------------------------- /src/lib/components/AuthorizerSignup.svelte: -------------------------------------------------------------------------------- 1 | 127 | 128 | {#if componentState.successMessage} 129 | 130 | {:else} 131 | {#if componentState.error} 132 | 133 | {/if} 134 |
135 | 136 | 140 | 148 |
149 | {errorData.email} 150 |
151 |
152 | 153 | 157 | 165 |
166 | {errorData.password} 167 |
168 |
169 | 170 | 174 | 184 |
185 | {errorData.confirmPassword} 186 |
187 |
188 | {#if state.config.is_strong_password_enabled} 189 | 190 |
191 | {/if} 192 | 203 | {#if componentState.loading} 204 | Processing ... 205 | {:else} 206 | Sign Up 207 | {/if} 208 | 209 | 210 | {#if setView} 211 | 212 |
213 | Already have an account? 214 | setView && setView(Views.Login)}>Log In 215 |
216 |
217 | {/if} 218 | {/if} 219 | 220 | 221 | -------------------------------------------------------------------------------- /src/lib/components/AuthorizerSocialLogin.svelte: -------------------------------------------------------------------------------- 1 | 41 | 42 |
43 | {#if state.config.is_apple_login_enabled} 44 |
45 | { 47 | if (window?.location) 48 | window.location.href = `${state.config.authorizerURL}/oauth_login/apple?${queryParams}`; 49 | }} 50 | > 51 | 52 | Sign in with Apple 53 | 54 |
55 |
56 | {/if} 57 | {#if state.config.is_google_login_enabled} 58 | { 60 | if (window?.location) 61 | window.location.href = `${state.config.authorizerURL}/oauth_login/google?${queryParams}`; 62 | }} 63 | > 64 | 65 | Sign in with Google 66 | 67 |
68 | {/if} 69 | {#if state.config.is_github_login_enabled} 70 | { 72 | if (window?.location) 73 | window.location.href = `${state.config.authorizerURL}/oauth_login/github?${queryParams}`; 74 | }} 75 | > 76 | 77 | Sign in with Github 78 | 79 |
80 | {/if} 81 | {#if state.config.is_facebook_login_enabled} 82 | { 84 | if (window?.location) 85 | window.location.href = `${state.config.authorizerURL}/oauth_login/facebook?${queryParams}`; 86 | }} 87 | > 88 | 89 | Sign in with Facebook 90 | 91 |
92 | {/if} 93 | {#if state.config.is_linkedin_login_enabled} 94 | { 96 | if (window?.location) 97 | window.location.href = `${state.config.authorizerURL}/oauth_login/linkedin?${queryParams}`; 98 | }} 99 | > 100 | 101 | Sign in with Linkedin 102 | 103 |
104 | {/if} 105 | {#if state.config.is_twitter_login_enabled} 106 | { 108 | if (window?.location) 109 | window.location.href = `${state.config.authorizerURL}/oauth_login/twitter?${queryParams}`; 110 | }} 111 | > 112 | 113 | Sign in with Twitter 114 | 115 |
116 | {/if} 117 | {#if state.config.is_microsoft_login_enabled} 118 | { 120 | if (window?.location) 121 | window.location.href = `${state.config.authorizerURL}/oauth_login/microsoft?${queryParams}`; 122 | }} 123 | > 124 | 125 | Sign in with Microsoft 126 | 127 |
128 | {/if} 129 | {#if hasSocialLogin && (state.config.is_basic_authentication_enabled || state.config.is_magic_link_login_enabled)} 130 | OR 131 | {/if} 132 |
133 | 134 | 135 | -------------------------------------------------------------------------------- /src/lib/components/AuthorizerVerifyOtp.svelte: -------------------------------------------------------------------------------- 1 | 108 | 109 | {#if componentState.successMessage} 110 | 115 | {/if} 116 | {#if componentState.error} 117 | 118 | {/if} 119 |

120 | Please enter the OTP you received on your email address. 121 |

122 |
123 |
124 | 125 | 129 | 137 |
138 | {otpError} 139 |
140 |
141 |
142 | 143 | {#if componentState.loading} 144 | Processing ... 145 | {:else} 146 | Submit 147 | {/if} 148 | 149 |
150 | {#if setView} 151 | 152 | {#if componentState.sendingOtp} 153 |
Sending ...
154 | {:else} 155 | Resend OTP 156 | {/if} 157 | {#if state.config.is_sign_up_enabled} 158 |
159 | Don't have an account? 160 | setView && setView(Views.Signup)}>Sign Up 161 |
162 | {/if} 163 |
164 | {/if} 165 | -------------------------------------------------------------------------------- /src/lib/components/Message.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | 14 |
{capitalizeFirstLetter(text)}
15 | {#if onClose} 16 | onClose && onClose()}> 17 | 18 | 19 | {/if} 20 |
21 |
22 | -------------------------------------------------------------------------------- /src/lib/components/PasswordStrengthIndicator.svelte: -------------------------------------------------------------------------------- 1 | 44 | 45 |
46 | 47 | 48 | 2 ? 'weak' : 'default'} /> 49 | 3 ? 'good' : 'default'} /> 50 | 4 ? 'strong' : 'default'} /> 51 | 5 ? 'veryStrong' : 'default'} /> 52 | {#if componentState.score} 53 |
{componentState.strength}
54 | {/if} 55 |
56 |

57 | Criteria for a strong password: 58 |

59 | 60 | 61 | 68 |
At least 6 characters
69 |
70 | 71 | 78 |
At least 1 lowercase letter
79 |
80 | 81 | 88 |
At least 1 uppercase letter
89 |
90 | 91 | 98 |
At least 1 numeric character
99 |
100 | 101 | 108 |
At least 1 special character
109 |
110 | 111 | 118 |
Maximum 36 characters
119 |
120 |
121 |
122 |
123 | 124 | 125 | -------------------------------------------------------------------------------- /src/lib/constants/index.ts: -------------------------------------------------------------------------------- 1 | export enum Views { 2 | Login, 3 | Signup, 4 | ForgotPassword 5 | } 6 | 7 | export enum ButtonAppearance { 8 | Primary, 9 | Default 10 | } 11 | 12 | export enum MessageType { 13 | Error, 14 | Success 15 | } 16 | 17 | export enum AuthorizerProviderActionType { 18 | SET_USER = 'SET_USER', 19 | SET_TOKEN = 'SET_TOKEN', 20 | SET_LOADING = 'SET_LOADING', 21 | SET_AUTH_DATA = 'SET_AUTH_DATA', 22 | SET_CONFIG = 'SET_CONFIG' 23 | } 24 | 25 | // TODO use based on theme primary color 26 | export const passwordStrengthIndicatorOpacity: Record = { 27 | default: 0.15, 28 | weak: 0.4, 29 | good: 0.6, 30 | strong: 0.8, 31 | veryStrong: 1 32 | }; 33 | -------------------------------------------------------------------------------- /src/lib/icons/Apple.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 | 6 | 7 |
8 | -------------------------------------------------------------------------------- /src/lib/icons/Close.svelte: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | -------------------------------------------------------------------------------- /src/lib/icons/Facebook.svelte: -------------------------------------------------------------------------------- 1 |
2 | 9 | 12 | 13 |
14 | -------------------------------------------------------------------------------- /src/lib/icons/Github.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 | 7 | 8 |
9 | -------------------------------------------------------------------------------- /src/lib/icons/Google.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 8 | 12 | 16 | 20 | 21 | 22 |
23 | -------------------------------------------------------------------------------- /src/lib/icons/Linkedin.svelte: -------------------------------------------------------------------------------- 1 |
2 | 11 |
12 | -------------------------------------------------------------------------------- /src/lib/icons/Microsoft.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | -------------------------------------------------------------------------------- /src/lib/icons/Twitter.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 | 7 | 8 |
9 | -------------------------------------------------------------------------------- /src/lib/icons/index.ts: -------------------------------------------------------------------------------- 1 | import Apple from './Apple.svelte'; 2 | import Close from './Close.svelte'; 3 | import Facebook from './Facebook.svelte'; 4 | import Github from './Github.svelte'; 5 | import Google from './Google.svelte'; 6 | import Linkedin from './Linkedin.svelte'; 7 | import Twitter from './Twitter.svelte'; 8 | import Microsoft from './Microsoft.svelte'; 9 | 10 | export { Apple, Facebook, Github, Google, Linkedin, Twitter, Close, Microsoft }; 11 | -------------------------------------------------------------------------------- /src/lib/index.ts: -------------------------------------------------------------------------------- 1 | // Reexport your entry components here 2 | import AuthorizerProvider from './components/AuthorizerProvider.svelte'; 3 | import AuthorizerSignup from './components/AuthorizerSignup.svelte'; 4 | import AuthorizerBasicAuthLogin from './components/AuthorizerBasicAuthLogin.svelte'; 5 | import AuthorizerMagicLinkLogin from './components/AuthorizerMagicLinkLogin.svelte'; 6 | import AuthorizerForgotPassword from './components/AuthorizerForgotPassword.svelte'; 7 | import AuthorizerSocialLogin from './components/AuthorizerSocialLogin.svelte'; 8 | import AuthorizerResetPassword from './components/AuthorizerResetPassword.svelte'; 9 | import AuthorizerVerifyOtp from './components/AuthorizerVerifyOtp.svelte'; 10 | import AuthorizerRoot from './components/AuthorizerRoot.svelte'; 11 | 12 | export { 13 | AuthorizerProvider, 14 | AuthorizerSignup, 15 | AuthorizerBasicAuthLogin, 16 | AuthorizerMagicLinkLogin, 17 | AuthorizerForgotPassword, 18 | AuthorizerSocialLogin, 19 | AuthorizerResetPassword, 20 | AuthorizerVerifyOtp, 21 | AuthorizerRoot as Authorizer 22 | }; 23 | -------------------------------------------------------------------------------- /src/lib/store/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-empty-function */ 2 | import { writable } from 'svelte/store'; 3 | import { Authorizer } from '@authorizerdev/authorizer-js'; 4 | import { hasWindow } from '../utils/window'; 5 | import type { AuthorizerState } from '$lib/types'; 6 | 7 | export const store = writable({ 8 | config: { 9 | authorizerURL: '', 10 | redirectURL: '/', 11 | client_id: '', 12 | is_google_login_enabled: false, 13 | is_github_login_enabled: false, 14 | is_facebook_login_enabled: false, 15 | is_linkedin_login_enabled: false, 16 | is_apple_login_enabled: false, 17 | is_twitter_login_enabled: false, 18 | is_microsoft_login_enabled: false, 19 | is_email_verification_enabled: false, 20 | is_basic_authentication_enabled: false, 21 | is_magic_link_login_enabled: false, 22 | is_sign_up_enabled: false, 23 | is_strong_password_enabled: true 24 | }, 25 | user: null, 26 | token: null, 27 | loading: false, 28 | setLoading: () => {}, 29 | setToken: () => {}, 30 | setUser: () => {}, 31 | setAuthData: () => {}, 32 | authorizerRef: new Authorizer({ 33 | authorizerURL: `http://localhost:8080`, 34 | redirectURL: hasWindow() ? window.location.origin : '/', 35 | clientID: '' 36 | }), 37 | logout: async () => {} 38 | }); 39 | -------------------------------------------------------------------------------- /src/lib/styledComponents/StyledButton.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 28 | 29 | 48 | -------------------------------------------------------------------------------- /src/lib/styledComponents/StyledFlex.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
17 | 18 |
19 | 20 | 25 | -------------------------------------------------------------------------------- /src/lib/styledComponents/StyledFooter.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 14 | -------------------------------------------------------------------------------- /src/lib/styledComponents/StyledFormGroup.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 | 7 | 8 | {#if hasError} 9 | 10 | {/if} 11 |
12 | 13 | 54 | -------------------------------------------------------------------------------- /src/lib/styledComponents/StyledLink.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | -------------------------------------------------------------------------------- /src/lib/styledComponents/StyledMessageWrapper.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
13 | 14 |
15 | 16 | 25 | -------------------------------------------------------------------------------- /src/lib/styledComponents/StyledPasswordStrength.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
11 | 12 |
13 | 14 | 24 | -------------------------------------------------------------------------------- /src/lib/styledComponents/StyledPasswordStrengthWrapper.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 10 | -------------------------------------------------------------------------------- /src/lib/styledComponents/StyledSeparator.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 29 | -------------------------------------------------------------------------------- /src/lib/styledComponents/StyledWrapper.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 | 19 | -------------------------------------------------------------------------------- /src/lib/styledComponents/index.ts: -------------------------------------------------------------------------------- 1 | import StyledWrapper from './StyledWrapper.svelte'; 2 | import StyledButton from './StyledButton.svelte'; 3 | import StyledLink from './StyledLink.svelte'; 4 | import StyledSeparator from './StyledSeparator.svelte'; 5 | import StyledFooter from './StyledFooter.svelte'; 6 | import StyledMessageWrapper from './StyledMessageWrapper.svelte'; 7 | import StyledFlex from './StyledFlex.svelte'; 8 | import StyledFormGroup from './StyledFormGroup.svelte'; 9 | import StyledPasswordStrength from './StyledPasswordStrength.svelte'; 10 | import StyledPasswordStrengthWrapper from './StyledPasswordStrengthWrapper.svelte'; 11 | 12 | export { 13 | StyledWrapper, 14 | StyledButton, 15 | StyledLink, 16 | StyledSeparator, 17 | StyledFooter, 18 | StyledMessageWrapper, 19 | StyledFlex, 20 | StyledFormGroup, 21 | StyledPasswordStrength, 22 | StyledPasswordStrengthWrapper 23 | }; 24 | -------------------------------------------------------------------------------- /src/lib/styles/default.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --authorizer-primary-color: #3b82f6; 3 | --authorizer-primary-disabled-color: #60a5fa; 4 | --authorizer-gray-color: #d1d5db; 5 | --authorizer-white-color: #ffffff; 6 | --authorizer-danger-color: #dc2626; 7 | --authorizer-success-color: #10b981; 8 | --authorizer-text-color: #374151; 9 | --authorizer-fonts-font-stack: -apple-system, system-ui, sans-serif; 10 | --authorizer-fonts-large-text: 18px; 11 | --authorizer-fonts-medium-text: 14px; 12 | --authorizer-fonts-small-text: 12px; 13 | --authorizer-fonts-tiny-text: 10px; 14 | --authorizer-radius-card: 5px; 15 | --authorizer-radius-button: 5px; 16 | --authorizer-radius-input: 5px; 17 | } 18 | -------------------------------------------------------------------------------- /src/lib/types/index.ts: -------------------------------------------------------------------------------- 1 | import type { AuthToken, User, Authorizer } from '@authorizerdev/authorizer-js'; 2 | import type { AuthorizerProviderActionType } from '../constants'; 3 | 4 | export type ConfigState = { 5 | authorizerURL?: string; 6 | redirectURL?: string; 7 | client_id?: string; 8 | is_google_login_enabled?: boolean; 9 | is_github_login_enabled?: boolean; 10 | is_facebook_login_enabled?: boolean; 11 | is_linkedin_login_enabled?: boolean; 12 | is_apple_login_enabled?: boolean; 13 | is_twitter_login_enabled?: boolean; 14 | is_microsoft_login_enabled?: boolean; 15 | is_email_verification_enabled?: boolean; 16 | is_basic_authentication_enabled?: boolean; 17 | is_magic_link_login_enabled?: boolean; 18 | is_sign_up_enabled?: boolean; 19 | is_strong_password_enabled?: boolean; 20 | }; 21 | 22 | export type AuthorizerProviderAction = { 23 | type: AuthorizerProviderActionType; 24 | payload: any; 25 | }; 26 | 27 | export type AuthorizerInputState = { 28 | user: User | null; 29 | token: AuthToken | null; 30 | loading: boolean; 31 | config: ConfigState; 32 | }; 33 | 34 | export type AuthorizerState = { 35 | user: User | null; 36 | token: AuthToken | null; 37 | loading: boolean; 38 | config: ConfigState; 39 | logout: () => Promise; 40 | setLoading: (data: boolean) => void; 41 | setUser: (data: null | User) => void; 42 | setToken: (data: null | AuthToken) => void; 43 | setAuthData: (data: AuthorizerInputState) => void; 44 | authorizerRef: Authorizer; 45 | }; 46 | 47 | export type OtpDataType = { 48 | isScreenVisible: boolean; 49 | email: string; 50 | }; 51 | -------------------------------------------------------------------------------- /src/lib/utils/common.ts: -------------------------------------------------------------------------------- 1 | import { hasWindow } from './window'; 2 | 3 | export const getIntervalDiff = (accessTokenExpiresAt: number): number => { 4 | const expiresAt = accessTokenExpiresAt * 1000 - 300000; 5 | const currentDate = new Date(); 6 | 7 | const millisecond = new Date(expiresAt).getTime() - currentDate.getTime(); 8 | return millisecond; 9 | }; 10 | 11 | export const getCrypto = () => { 12 | //ie 11.x uses msCrypto 13 | return hasWindow() ? window.crypto : null; 14 | }; 15 | 16 | export const createRandomString = (): string => { 17 | const charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_~.'; 18 | let random = ''; 19 | const crypto = getCrypto(); 20 | if (crypto) { 21 | const randomValues = Array.from(crypto.getRandomValues(new Uint8Array(43))); 22 | randomValues.forEach((v) => (random += charset[v % charset.length])); 23 | } 24 | return random; 25 | }; 26 | 27 | export const createQueryParams = (params: Record): string => { 28 | return Object.keys(params) 29 | .filter((k) => typeof params[k] !== 'undefined') 30 | .map((k) => encodeURIComponent(k) + '=' + encodeURIComponent(params[k])) 31 | .join('&'); 32 | }; 33 | 34 | export const isValidEmail = (email: string): boolean => { 35 | const regex = 36 | /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; 37 | const lowerCaseEmail = (email || ``).trim().toLocaleLowerCase(); 38 | return regex.test(lowerCaseEmail); 39 | }; 40 | 41 | export const capitalizeFirstLetter = (data: string): string => { 42 | if (!data) return ''; 43 | return data ? data.charAt(0).toUpperCase() + data.slice(1) : ``; 44 | }; 45 | 46 | export const isValidOtp = (otp: string): boolean => { 47 | const re = /^([A-Z0-9]{6})$/; 48 | const trimmedOTP = (otp || ``).trim(); 49 | return re.test(trimmedOTP); 50 | }; 51 | 52 | export const formatErrorMessage = (message: string): string => { 53 | return message.replace(`[GraphQL] `, ''); 54 | }; 55 | 56 | export const hasSpecialChar = (char: string): boolean => { 57 | const re = /[`!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?~]/; 58 | return re.test(char); 59 | }; 60 | 61 | export const validatePassword = ( 62 | value: string 63 | ): { 64 | score: number; 65 | strength: string; 66 | hasSixChar: boolean; 67 | hasLowerCase: boolean; 68 | hasUpperCase: boolean; 69 | hasNumericChar: boolean; 70 | hasSpecialChar: boolean; 71 | maxThirtySixChar: boolean; 72 | isValid: boolean; 73 | } => { 74 | const res = { 75 | score: 0, 76 | strength: '', 77 | hasSixChar: false, 78 | hasLowerCase: false, 79 | hasUpperCase: false, 80 | hasNumericChar: false, 81 | hasSpecialChar: false, 82 | maxThirtySixChar: false 83 | }; 84 | 85 | if (value.length >= 6) { 86 | res.score = res.score + 1; 87 | res.hasSixChar = true; 88 | } 89 | 90 | if (value.length > 0 && value.length <= 36) { 91 | res.score = res.score + 1; 92 | res.maxThirtySixChar = true; 93 | } 94 | 95 | Array.from(value).forEach((char: any) => { 96 | if (char >= 'A' && char <= 'Z' && !res.hasUpperCase) { 97 | res.score = res.score + 1; 98 | res.hasUpperCase = true; 99 | } else if (char >= 'a' && char <= 'z' && !res.hasLowerCase) { 100 | res.score = res.score + 1; 101 | res.hasLowerCase = true; 102 | } else if (char >= '0' && char <= '9' && !res.hasNumericChar) { 103 | res.score = res.score + 1; 104 | res.hasNumericChar = true; 105 | } else if (hasSpecialChar(char) && !res.hasSpecialChar) { 106 | res.score = res.score + 1; 107 | res.hasSpecialChar = true; 108 | } 109 | }); 110 | 111 | if (res.score <= 2) { 112 | res.strength = 'Weak'; 113 | } else if (res.score <= 4) { 114 | res.strength = 'Good'; 115 | } else if (res.score <= 5) { 116 | res.strength = 'Strong'; 117 | } else { 118 | res.strength = 'Very Strong'; 119 | } 120 | 121 | const isValid = Object.values(res).every((i) => Boolean(i)); 122 | return { ...res, isValid }; 123 | }; 124 | -------------------------------------------------------------------------------- /src/lib/utils/url.ts: -------------------------------------------------------------------------------- 1 | import { hasWindow } from './window'; 2 | 3 | export const getSearchParams = (search = '') => { 4 | let searchPrams = search; 5 | if (!searchPrams && hasWindow()) { 6 | searchPrams = window.location.search; 7 | } 8 | const urlSearchParams = new URLSearchParams(`${searchPrams}`); 9 | const params = Object.fromEntries(urlSearchParams.entries()); 10 | return params; 11 | }; 12 | -------------------------------------------------------------------------------- /src/lib/utils/window.ts: -------------------------------------------------------------------------------- 1 | export const hasWindow = (): boolean => typeof window !== 'undefined'; 2 | -------------------------------------------------------------------------------- /src/routes/+layout.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 |
7 |
8 | 14 | 15 | 16 |
17 |
18 | 19 | 43 | -------------------------------------------------------------------------------- /src/routes/+page.svelte: -------------------------------------------------------------------------------- 1 | 20 | 21 | {#if state.token} 22 |
23 |

Hey 👋,

24 |

Thank you for joining Authorizer demo app.

25 |

26 | Your email address is 27 | 28 | {state.user?.email} 29 | 30 |

31 |
32 | {#if state.loading} 33 |

Processing....

34 | {:else} 35 |

Logout

36 | {/if} 37 |
38 | {:else} 39 | 44 | {/if} 45 | 46 | 54 | -------------------------------------------------------------------------------- /src/routes/reset-password/+page.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |

Reset Password

6 |
7 | 8 | -------------------------------------------------------------------------------- /static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/authorizerdev/authorizer-svelte/a558bf9848c0536a3d4b4e54cb2ed7fbcf647e95/static/favicon.png -------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | import adapter from '@sveltejs/adapter-auto'; 2 | import preprocess from 'svelte-preprocess'; 3 | 4 | /** @type {import('@sveltejs/kit').Config} */ 5 | const config = { 6 | // Consult https://github.com/sveltejs/svelte-preprocess 7 | // for more information about preprocessors 8 | preprocess: preprocess(), 9 | 10 | kit: { 11 | adapter: adapter() 12 | } 13 | }; 14 | 15 | export default config; 16 | -------------------------------------------------------------------------------- /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 relevant includes/excludes 16 | // from the referenced tsconfig.json - TypeScript does not merge them in 17 | } 18 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { sveltekit } from '@sveltejs/kit/vite'; 2 | import type { UserConfig } from 'vite'; 3 | 4 | const config: UserConfig = { 5 | plugins: [sveltekit()] 6 | }; 7 | 8 | export default config; 9 | --------------------------------------------------------------------------------