Skip to content

Commit 00b664a

Browse files
author
ThangHuuVu
committedDec 14, 2022
🔄 Synced local '.' with remote 'apps/example-sveltekit'
1 parent 36a19f4 commit 00b664a

21 files changed

+425
-0
lines changed
 

‎.env.example

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
GITHUB_ID=
2+
GITHUB_SECRET=
3+
# On UNIX systems you can use `openssl rand -hex 32` or
4+
# https://generate-secret.vercel.app/32 to generate a secret.
5+
AUTH_SECRET=

‎.eslintignore

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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

‎.eslintrc.cjs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
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+
};

‎.gitignore

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
.DS_Store
2+
node_modules
3+
/build
4+
/.svelte-kit
5+
/package
6+
.env
7+
.env.*
8+
!.env.example
9+
.vercel
10+
.output
11+
vite.config.js.timestamp-*
12+
vite.config.ts.timestamp-*

‎.prettierignore

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
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

‎.prettierrc

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"semi": false,
3+
"plugins": ["prettier-plugin-svelte"],
4+
"pluginSearchDirs": ["."],
5+
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
6+
}

‎README.md

+75
Original file line numberDiff line numberDiff line change
@@ -1 +1,76 @@
1+
# SvelteKit + NextAuth.js Playground
12

3+
NextAuth.js is committed to bringing easy authentication to other frameworks. https://github.com/nextauthjs/next-auth/issues/2294
4+
5+
SvelteKit support with NextAuth.js is currently experimental. This directory contains a minimal, proof-of-concept application. Parts of this is expected to be abstracted away into a package like `@next-auth/sveltekit`
6+
7+
## Running this Demo
8+
9+
- Copy `.env.example` to `.env`
10+
- In `.env`, set `GITHUB_CLIENT_ID` and `GITHUB_CLIENT_SECRET`
11+
- See [https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app](https://docs.github.com/en/developers/apps/building-oauth-apps/creating-an-oauth-app))
12+
- When creating the OAuth app, set "Homepage URL" to `http://localhost:5173` and Authorization callack URL to `http://localhost:5173/api/auth/callback/github`
13+
- In `.env`, set `NEXTAUTH_SECRET` to any random string
14+
- Build and run the application: `yarn build && yarn start`
15+
16+
## Existing Project
17+
18+
### Add API Route
19+
20+
To add NextAuth.js to a project create a file called `[...nextauth]/+server.js` in routes/api/auth. This contains the dynamic route handler for NextAuth.js which will also contain all of your global NextAuth.js configurations.
21+
22+
```ts
23+
import { NextAuth, options } from "$lib/next-auth"
24+
25+
export const { GET, POST } = NextAuth(options)
26+
```
27+
28+
### Add [hook](https://kit.svelte.dev/docs/hooks)
29+
30+
```ts
31+
import type { Handle } from "@sveltejs/kit"
32+
import { getServerSession, options as nextAuthOptions } from "$lib/next-auth"
33+
34+
export const handle: Handle = async function handle({
35+
event,
36+
resolve,
37+
}): Promise<Response> {
38+
const session = await getServerSession(event.request, nextAuthOptions)
39+
event.locals.session = session
40+
41+
return resolve(event)
42+
}
43+
```
44+
45+
### Load Session from Primary Layout
46+
47+
```ts
48+
// src/lib/routes/+layout.server.ts
49+
import type { LayoutServerLoad } from "./$types"
50+
51+
export const load: LayoutServerLoad = ({ locals }) => {
52+
return {
53+
session: locals.session,
54+
}
55+
}
56+
```
57+
58+
### Protecting a Route
59+
60+
```ts
61+
// src/lib/routes/protected/+page.ts
62+
import { redirect } from "@sveltejs/kit"
63+
import type { PageLoad } from "./$types"
64+
65+
export const load: PageLoad = async ({ parent }) => {
66+
const { session } = await parent()
67+
if (!session?.user) {
68+
throw redirect(302, "/")
69+
}
70+
return {}
71+
}
72+
```
73+
74+
## Packaging lib
75+
76+
Refer to https://kit.svelte.dev/docs/packaging

‎package.json

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"scripts": {
3+
"dev": "vite dev",
4+
"build": "vite build",
5+
"preview": "vite preview",
6+
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
7+
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
8+
},
9+
"devDependencies": {
10+
"@sveltejs/adapter-auto": "next",
11+
"@sveltejs/kit": "next",
12+
"svelte": "3.55.0",
13+
"svelte-check": "2.10.2",
14+
"typescript": "4.9.4",
15+
"vite": "4.0.1"
16+
},
17+
"dependencies": {
18+
"cookie": "0.5.0",
19+
"@auth/core": "workspace:*",
20+
"@auth/sveltekit": "workspace:*"
21+
},
22+
"type": "module"
23+
}

‎src/app.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/// <reference types="@auth/sveltekit" />

‎src/app.html

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<link rel="icon" href="%sveltekit.assets%/favicon.ico" />
6+
<meta name="viewport" content="width=device-width" />
7+
%sveltekit.head%
8+
</head>
9+
10+
<body>
11+
<div>%sveltekit.body%</div>
12+
</body>
13+
</html>

‎src/hooks.server.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import SvelteKitAuth from "@auth/sveltekit"
2+
import GitHub from "@auth/core/providers/github"
3+
import { GITHUB_ID, GITHUB_SECRET } from "$env/static/private"
4+
5+
export const handle = SvelteKitAuth({
6+
providers: [GitHub({ clientId: GITHUB_ID, clientSecret: GITHUB_SECRET })],
7+
})

‎src/lib/SignInButton.svelte

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<script lang="ts">
2+
export let provider: any
3+
</script>
4+
5+
<form action={provider.signinUrl} method="POST">
6+
{#if provider.callbackUrl}
7+
<input type="hidden" name="callbackUrl" value={provider.callbackUrl} />
8+
{/if}
9+
<button type="submit" class="button">
10+
<slot>Sign in with {provider.name}</slot>
11+
</button>
12+
</form>

‎src/routes/+layout.server.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import type { LayoutServerLoad } from "./$types"
2+
3+
export const load: LayoutServerLoad = async (event) => {
4+
return {
5+
session: await event.locals.getSession(),
6+
}
7+
}

‎src/routes/+layout.svelte

+151
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
<script lang="ts">
2+
import { page } from "$app/stores"
3+
</script>
4+
5+
<div>
6+
<header>
7+
<div class="signedInStatus">
8+
<p class="nojs-show loaded">
9+
{#if $page.data.session}
10+
{#if $page.data.session.user?.image}
11+
<span
12+
style="background-image: url('{$page.data.session.user.image}')"
13+
class="avatar"
14+
/>
15+
{/if}
16+
<span class="signedInText">
17+
<small>Signed in as</small><br />
18+
<strong
19+
>{$page.data.session.user?.email ??
20+
$page.data.session.user?.name}</strong
21+
>
22+
</span>
23+
<a href="/auth/signout" class="button">Sign out</a>
24+
{:else}
25+
<span class="notSignedInText">You are not signed in</span>
26+
<a href="/auth/signin" class="buttonPrimary">Sign in</a>
27+
{/if}
28+
</p>
29+
</div>
30+
<nav>
31+
<ul class="navItems">
32+
<li class="navItem"><a href="/">Home</a></li>
33+
<li class="navItem"><a href="/protected">Protected</a></li>
34+
</ul>
35+
</nav>
36+
</header>
37+
<slot />
38+
</div>
39+
40+
<style>
41+
:global(body) {
42+
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont,
43+
"Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif,
44+
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
45+
"Noto Color Emoji";
46+
padding: 0 1rem 1rem 1rem;
47+
max-width: 680px;
48+
margin: 0 auto;
49+
background: #fff;
50+
color: #333;
51+
}
52+
:global(li),
53+
:global(p) {
54+
line-height: 1.5rem;
55+
}
56+
:global(a) {
57+
font-weight: 500;
58+
}
59+
:global(hr) {
60+
border: 1px solid #ddd;
61+
}
62+
:global(iframe) {
63+
background: #ccc;
64+
border: 1px solid #ccc;
65+
height: 10rem;
66+
width: 100%;
67+
border-radius: 0.5rem;
68+
filter: invert(1);
69+
}
70+
71+
.nojs-show {
72+
opacity: 1;
73+
top: 0;
74+
}
75+
.signedInStatus {
76+
display: block;
77+
min-height: 4rem;
78+
width: 100%;
79+
}
80+
.loaded {
81+
position: relative;
82+
top: 0;
83+
opacity: 1;
84+
overflow: hidden;
85+
border-radius: 0 0 0.6rem 0.6rem;
86+
padding: 0.6rem 1rem;
87+
margin: 0;
88+
background-color: rgba(0, 0, 0, 0.05);
89+
transition: all 0.2s ease-in;
90+
}
91+
.signedInText,
92+
.notSignedInText {
93+
position: absolute;
94+
padding-top: 0.8rem;
95+
left: 1rem;
96+
right: 6.5rem;
97+
white-space: nowrap;
98+
text-overflow: ellipsis;
99+
overflow: hidden;
100+
display: inherit;
101+
z-index: 1;
102+
line-height: 1.3rem;
103+
}
104+
.signedInText {
105+
padding-top: 0rem;
106+
left: 4.6rem;
107+
}
108+
.avatar {
109+
border-radius: 2rem;
110+
float: left;
111+
height: 2.8rem;
112+
width: 2.8rem;
113+
background-color: white;
114+
background-size: cover;
115+
background-repeat: no-repeat;
116+
}
117+
.button,
118+
.buttonPrimary {
119+
float: right;
120+
margin-right: -0.4rem;
121+
font-weight: 500;
122+
border-radius: 0.3rem;
123+
cursor: pointer;
124+
font-size: 1rem;
125+
line-height: 1.4rem;
126+
padding: 0.7rem 0.8rem;
127+
position: relative;
128+
z-index: 10;
129+
background-color: transparent;
130+
color: #555;
131+
}
132+
.buttonPrimary {
133+
background-color: #346df1;
134+
border-color: #346df1;
135+
color: #fff;
136+
text-decoration: none;
137+
padding: 0.7rem 1.4rem;
138+
}
139+
.buttonPrimary:hover {
140+
box-shadow: inset 0 0 5rem rgba(0, 0, 0, 0.2);
141+
}
142+
.navItems {
143+
margin-bottom: 2rem;
144+
padding: 0;
145+
list-style: none;
146+
}
147+
.navItem {
148+
display: inline-block;
149+
margin-right: 1rem;
150+
}
151+
</style>

‎src/routes/+page.svelte

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<h1>SvelteKit Auth Example</h1>
2+
<p>
3+
This is an example site to demonstrate how to use <a
4+
href="https://kit.svelte.dev/">SvelteKit</a
5+
>
6+
with <a href="https://sveltekit.authjs.dev">SvelteKit Auth</a> for authentication.
7+
</p>

‎src/routes/protected/+page.svelte

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<script lang="ts">
2+
import { page } from "$app/stores"
3+
</script>
4+
5+
<h1>Protected page</h1>
6+
<p>
7+
This is a protected content. You can access this content because you are
8+
signed in.
9+
</p>
10+
<p>Session expiry: {$page.data.session?.expires}</p>

‎src/routes/protected/+page.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { redirect } from "@sveltejs/kit"
2+
import type { PageLoad } from "./$types"
3+
4+
export const load: PageLoad = async ({ parent }) => {
5+
const { session } = await parent()
6+
if (!session?.user) {
7+
throw redirect(302, "/")
8+
}
9+
return {}
10+
}

‎static/favicon.ico

1.53 KB
Binary file not shown.

‎svelte.config.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import adapter from '@sveltejs/adapter-auto';
2+
import { vitePreprocess } from '@sveltejs/kit/vite';
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: adapter()
12+
}
13+
};
14+
15+
export default config;

‎tsconfig.json

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
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+
}

‎vite.config.js

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { sveltekit } from "@sveltejs/kit/vite"
2+
3+
/** @type {import('vite').UserConfig} */
4+
const config = {
5+
plugins: [sveltekit()],
6+
}
7+
8+
export default config

0 commit comments

Comments
 (0)
Please sign in to comment.