39
loading...
This website collects cookies to deliver better user experience
🎓Tutorial: What you will learn
* How to create an OAuth Application using Github
* How to redirect requests using SvelteKit
* How to handle OAuth Callbacks
* How to use the Access Token to get Github User Information
* How to store http-only secure cookies using SvelteKit
* How to use the hooks middleware in SvelteKit
* How to read session information in the SvelteKit client
mkdir authy
cd authy
npm init svelte@next
create-svelte version 2.0.0-next.73
Welcome to SvelteKit!
This is beta software; expect bugs and missing features.
If you encounter a problem, open an issue on https://github.com/sveltejs/kit/issues if none exists already.
? Directory not empty. Continue? › (y/N) y
? Which Svelte app template? › - Use arrow-keys. Return to submit.
[Choose Skeleton project]
? Use TypeScript? › No / Yes -> No
? Add ESLint for code linting? › No / Yes -> No
? Add Prettier for code formatting? › No / Yes -> No
VITE_CLIENT_ID=XXXXXXX
VITE_CLIENT_SECRET=XXXXXXXXXX
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>
<a href="/login">
<button>Login using Github</button>
</a>
export async function get(req) {
return {
body: 'Hello'
}
}
type Headers = Record<string, string>;
type Request<Locals = Record<string, any>, Body = unknown> = {
method: string;
host: string;
headers: Headers;
path: string;
params: Record<string, string>;
query: URLSearchParams;
rawBody: string | Uint8Array;
body: ParameterizedBody<Body>;
locals: Locals; // populated by hooks handle
};
type EndpointOutput = {
status?: number;
headers?: Headers;
body?: string | Uint8Array | JSONValue;
};
type RequestHandler<Locals = Record<string, any>> = (
request: Request<Locals>
) => void | EndpointOutput | Promise<EndpointOutput>;
const ghAuthURL = 'https://github.com/login/oauth/authorize'
const clientId = import.meta.env.VITE_CLIENT_ID
export async function get(req) {
const sessionId = '1234'
return {
status: 302,
headers: {
location: `${ghAuthURL}?client_id=${clientId}&state=${sessionId}`
}
}
}
export async function get(req) {
return {
body: 'callback'
}
}
yarn add node-fetch
import fetch from 'node-fetch'
const tokenURL = 'https://github.com/login/oauth/access_token'
const clientId = import.meta.env.VITE_CLIENT_ID
const secret = import.meta.env.VITE_CLIENT_SECRET
export async function get(req) {
const code = req.query.get('code')
const accessToken = await getAccessToken(code)
return {
body: JSON.stringify(accessToken)
}
}
function getAccessToken(code) {
return fetch(tokenURL, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify({
client_id: clientId,
client_secret: secret,
code
})
}).then(r => r.json())
.then(r => r.access_token)
}
const userURL = 'https://api.github.com/user'
function getUser(accessToken) {
return fetch(userURL, {
headers: {
Accept: 'application/json',
Authorization: `Bearer ${accessToken}`
}
})
.then(r => r.json())
}
export async function get(req) {
const code = req.query.get('code')
const accessToken = await getAccessToken(code)
const user = await getUser(accessToken)
return {
body: JSON.stringify(user)
}
}
import cookie from 'cookie'
export async function handle({request, resolve}) {
const cookies = cookie.parse(request.headers.cookie || '')
// code here happends before the endpoint or page is called
const response = await resolve(request)
// code here happens after the endpoint or page is called
return response
}
import cookie from 'cookie'
export async function handle({ request, resolve }) {
const cookies = cookie.parse(request.headers.cookie || '')
// code here happends before the endpoint or page is called
const response = await resolve(request)
// code here happens after the endpoint or page is called
response.headers['set-cookie'] = `user=${request.locals.user || ''}; Path=/; HttpOnly`
return response
}
import cookie from 'cookie'
export async function handle({ request, resolve }) {
const cookies = cookie.parse(request.headers.cookie || '')
// code here happends before the endpoint or page is called
request.locals.user = cookies.user
console.log({ user: request.locals.user })
const response = await resolve(request)
// code here happens after the endpoint or page is called
response.headers['set-cookie'] = `user=${request.locals.user || ''}; Path=/; HttpOnly`
return response
}
export async function get(req) {
const code = req.query.get('code')
const accessToken = await getAccessToken(code)
const user = await getUser(accessToken)
// this mutates the locals object on the request
// and will be read by the hooks/handle function
// after the resolve
req.locals.user = user.login
return {
status: 302,
headers: {
location: '/'
}
}
}
export async function getSession(request) {
return {
user: request.locals.user
}
}
<script context="module">
export async function load({ session }) {
return {
props: {
user: session.user,
},
};
}
</script>
<script>
export let user
</script>
<h1>Welcome to SvelteKit</h1>
<p>
Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation
</p>
{#if user}
<h2>Welcome {user}</h2>
<a href="/logout">
<button>Logout</button>
</a>
{:else}
<a href="/login">
<button>Login using Github</button>
</a>
{/if}
export async function get(req) {
req.locals.user = null
console.log(req.locals.user)
return {
status: 302,
headers: {
location: '/'
}
}
}
<script context="module">
export async function load({page, session}) {
if (/^\/admin\/(.*)/.test(page.path) && session.user === '') {
return { redirect: '/', status: 302 }
}
return { props: {} }
}
</script>
<slot />
Demo Repository: https://github.com/hyper63/tutorial-sveltekit-authentication