mirror of
https://github.com/LukeHagar/website.git
synced 2025-12-10 12:57:49 +00:00
feat: svelte ssr auth
This commit is contained in:
10
src/routes/docs/tutorials/sveltekit-ssr-auth/+layout.svelte
Normal file
10
src/routes/docs/tutorials/sveltekit-ssr-auth/+layout.svelte
Normal file
@@ -0,0 +1,10 @@
|
||||
<script lang="ts">
|
||||
import { globToTutorial } from '$lib/utils/tutorials.js';
|
||||
import { setContext } from 'svelte';
|
||||
|
||||
export let data;
|
||||
const tutorials = globToTutorial(data);
|
||||
setContext('tutorials', tutorials);
|
||||
</script>
|
||||
|
||||
<slot />
|
||||
11
src/routes/docs/tutorials/sveltekit-ssr-auth/+layout.ts
Normal file
11
src/routes/docs/tutorials/sveltekit-ssr-auth/+layout.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import type { LayoutLoad } from './$types';
|
||||
|
||||
export const load: LayoutLoad = ({ url }) => {
|
||||
const tutorials = import.meta.glob('./**/*.markdoc', {
|
||||
eager: true
|
||||
});
|
||||
return {
|
||||
tutorials,
|
||||
pathname: url.pathname
|
||||
};
|
||||
};
|
||||
6
src/routes/docs/tutorials/sveltekit-ssr-auth/+page.ts
Normal file
6
src/routes/docs/tutorials/sveltekit-ssr-auth/+page.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
import type { PageLoad } from './$types';
|
||||
|
||||
export const load: PageLoad = async () => {
|
||||
throw redirect(303, '/docs/tutorials/sveltekit-auth/step-1');
|
||||
};
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Server Side Rendering with SvelteKit
|
||||
description: Add SSR Authentication to your SvelteKit app with Appwrite
|
||||
step: 1
|
||||
difficulty: beginner
|
||||
readtime: 20
|
||||
framework: SvelteKit
|
||||
category: Auth
|
||||
---
|
||||
|
||||
Appwrite takes away the stress of building and maintaining a backend. Appwrite helps implement authentication, databases, file storage, and respond to real-time events with **secure** APIs out of the box.
|
||||
If you're a Svelte developer, the examples in this guide show you how Appwrite can help you add authentication to Svelte apps faster.
|
||||
|
||||
## Before you start
|
||||
|
||||
Even if you've never tried Appwrite, you will get an idea of what it'll feel like to build with Svelte and Appwrite.
|
||||
|
||||
If you're inspired and wish to follow along, make sure you've followed [Start with Svelte](https://appwrite.io/docs/quick-starts/sveltekit) first.
|
||||
You can also clone the [Demos for svelte](https://github.com/appwrite/demos-for-svelte) examples and follow along by looking at the code.
|
||||
@@ -0,0 +1,53 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Create project
|
||||
description: Add Authentication to a SvelteKit project using Appwrite.
|
||||
step: 2
|
||||
---
|
||||
|
||||
|
||||
Create a Svelte project using [SvelteKit](https://kit.svelte.dev/docs/creating-a-project).
|
||||
|
||||
```sh
|
||||
npm create svelte@latest
|
||||
```
|
||||
|
||||
The command will give you a prompt with several project types. We'll be starting with a skeleton project.
|
||||
|
||||
The prompt will be something similar to this.
|
||||
|
||||
```sh
|
||||
create-svelte version 3.2.0
|
||||
|
||||
┌ Welcome to SvelteKit!
|
||||
│
|
||||
◇ Where should we create your project?
|
||||
│ my-svelte-project
|
||||
│
|
||||
◇ Which Svelte app template?
|
||||
│ Skeleton project
|
||||
│
|
||||
◇ Add type checking with TypeScript?
|
||||
│ Yes, using JavaScript with JSDoc comments
|
||||
│
|
||||
◇ Select additional options (use arrow keys/space bar)
|
||||
│ Add ESLint for code linting
|
||||
│
|
||||
└ Your project is ready!
|
||||
```
|
||||
|
||||
After the prompt is finished, you can head over to the newly create project.
|
||||
|
||||
```sh
|
||||
cd my-svelte-project
|
||||
npm install
|
||||
```
|
||||
|
||||
## Adding `node-appwrite` to Your Svelte App
|
||||
|
||||
Appwrite provides a Node SDK that can be used in your Svelte apps. You can use Appwrite by installing the Node SDK as an NPM package.
|
||||
The Node SDK is intended for server-side use. If you want to use Appwrite in a client-side application, you should [use the Web SDK instead](/docs/tutorials/svelte-auth).
|
||||
|
||||
```sh
|
||||
npm install node-appwrite
|
||||
```
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Initialize SDK
|
||||
description: Add Authentication to a SvelteKit project using Appwrite.
|
||||
step: 3
|
||||
---
|
||||
Before you can use Appwrite, you need to create the Appwrite `Client` and set the project ID and endpoint.
|
||||
The client is then used to create services like `Databases` and `Account`, so they all point to the same Appwrite project.
|
||||
|
||||
Create a function to build services you need in a file like `src/lib/server/appwrite.js` and **exporting the instances**.
|
||||
|
||||
As part of the function, set the current user's session if they are logged in. This is done by accessing the session cookie from the request and calling the `setSession(session)` with the cookie value.
|
||||
|
||||
```js
|
||||
// src/lib/server/appwrite.js
|
||||
import { Client, Account } from 'node-appwrite';
|
||||
import { APPWRITE_KEY } from '$env/static/private';
|
||||
import { PUBLIC_APPWRITE_ENDPOINT, PUBLIC_APPWRITE_PROJECT_ID } from '$env/static/public';
|
||||
|
||||
export const SESSION_COOKIE = 'my-custom-session';
|
||||
|
||||
export function createAppwriteClient(event) {
|
||||
// Build the Appwrite client
|
||||
const client = new Client()
|
||||
.setEndpoint(PUBLIC_APPWRITE_ENDPOINT)
|
||||
.setProject(PUBLIC_APPWRITE_PROJECT_ID);
|
||||
|
||||
// Set the API key for the client
|
||||
client.setKey(APPWRITE_KEY);
|
||||
|
||||
// Extract our custom domain's session cookie from the request
|
||||
const session = event.cookies.get(SESSION_COOKIE);
|
||||
if (session) client.setSession(session);
|
||||
|
||||
// Return the services we want to use.
|
||||
// This allows us to use syntax like:
|
||||
// import { createAppwriteClient } from '$lib/server/appwrite';
|
||||
//
|
||||
// const { account } = createAppwriteClient(event);
|
||||
// const user = await account.get();
|
||||
return {
|
||||
get account() {
|
||||
return new Account(client);
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
`APPWRITE_KEY`, `PUBLIC_APPWRITE_ENDPOINT` and `PUBLIC_APPWRITE_PROJECT` are environment variables that are exported in your project's [.env file](https://kit.svelte.dev/docs/modules#$env-dynamic-public).
|
||||
|
||||
You can get the values for these variables from the Appwrite console. The `PUBLIC_APPWRITE_ENDPOINT` and `PUBLIC_APPWRITE_PROJECT` are the endpoint and project ID for your Appwrite project.
|
||||
|
||||
For example, your `.env` might look something similar to this.
|
||||
|
||||
```text
|
||||
APPWRITE_KEY=4d5e6f7g8h9i0j1k2l3m4n5o
|
||||
PUBLIC_APPWRITE_ENDPOINT=https://cloud.appwrite.io/v1
|
||||
PUBLIC_APPWRITE_PROJECT=642sdddf85b440dc7e5bf
|
||||
```
|
||||
|
||||
For this tutorial you'll need an API key with the following scopes:
|
||||
- `accounts.read`
|
||||
- `accounts.write`
|
||||
- `sessions.read`
|
||||
- `sessions.write`
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Add a server hook
|
||||
description: Add Authentication to a SvelteKit project using Appwrite.
|
||||
step: 4
|
||||
---
|
||||
|
||||
SvelteKit hooks which are functions that run on the server before a page is displayed to the user. SvelteKit locals are a way to store data that is specific to the current request. We can use this to store the user's account data, so that it is available to all pages.
|
||||
|
||||
Create a new file in the `src/hooks` directory called `server.js`:
|
||||
```js
|
||||
// src/hooks.server.js
|
||||
import { createAppwriteClient } from '$lib/server/appwrite';
|
||||
|
||||
export async function handle({ event, resolve }) {
|
||||
// Use our helper function to create the Appwrite client.
|
||||
const { account } = createAppwriteClient(event);
|
||||
|
||||
// Let's store the current logged in user in locals,
|
||||
// for easy access in our other routes.
|
||||
try {
|
||||
const user = await account.get();
|
||||
event.locals.user = user;
|
||||
} catch (error) {}
|
||||
|
||||
// Continue with the request.
|
||||
return resolve(event);
|
||||
}
|
||||
```
|
||||
|
||||
To ensure the `locals` object is typed correctly, we can add a type definition for it in the `env.d.ts` file:
|
||||
|
||||
```ts
|
||||
import type { Models } from 'node-appwrite';
|
||||
import type { AppwriteService } from '$lib/server/appwrite';
|
||||
|
||||
// See https://kit.svelte.dev/docs/types#app
|
||||
// for information about these interfaces
|
||||
declare global {
|
||||
namespace App {
|
||||
// interface Error {}
|
||||
interface Locals {
|
||||
user: Models.User<Preferences> | null;
|
||||
}
|
||||
// interface PageData {}
|
||||
// interface Platform {}
|
||||
}
|
||||
}
|
||||
|
||||
export {};
|
||||
```
|
||||
|
||||
Now, use the `locals` object in the home page to redirect based on the user's login status. Create a new file in the `src/routes` directory called `+page.server.js`:
|
||||
|
||||
```js
|
||||
import { createAppwriteClient } from '$lib/server/appwrite.js';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
|
||||
export async function load({ locals }) {
|
||||
// Access our user from locals.
|
||||
if (!locals.user) {
|
||||
// If no user is logged in, redirect to the sign in page.
|
||||
throw redirect(301, '/signin');
|
||||
}
|
||||
|
||||
// If the user is logged in, redirect to the account page.
|
||||
throw redirect(301, '/account');
|
||||
}
|
||||
```
|
||||
|
||||
When a user visits the home page, they will be redirected to the sign in page if they are not logged in, or to the account page if they are logged in.
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Create sign in page
|
||||
description: Add Authentication to a SvelteKit project using Appwrite.
|
||||
step: 5
|
||||
---
|
||||
|
||||
We can now implement our sign in page. Create a `+page.svelte` file in the `src/routes/signin` directory:
|
||||
|
||||
```svelte
|
||||
<!-- src/routes/sigin/+page.svelte -->
|
||||
<form method="post">
|
||||
<input id="email" placeholder="Email" type="email" />
|
||||
<input id="password" placeholder="Password" type="password" />
|
||||
<button type="submit">Sign in</button>
|
||||
</form>
|
||||
```
|
||||
|
||||
This is an HTML form with an email and password input. When the form is submitted, we want to send the email and password to Appwrite to authenticate the user. To use SvelteKit form actions we create a `+page.server.js` file in the same directory:
|
||||
|
||||
```javascript
|
||||
import { SESSION_COOKIE, createAppwriteClient } from '$lib/server/appwrite.js';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
|
||||
export const actions = {
|
||||
default: async (event) => {
|
||||
// Extract the form data.
|
||||
const form = await event.request.formData();
|
||||
const email = form.get('email') as string;
|
||||
const password = form.get('password') as string;
|
||||
|
||||
// Create the Appwrite client.
|
||||
const { account } = createAppwriteClient(event);
|
||||
|
||||
// Create the session using the client
|
||||
const session = await account.createEmailPasswordSession(email, password);
|
||||
|
||||
// Set the session cookie with the secret
|
||||
event.cookies.set(SESSION_COOKIE, session.secret, {
|
||||
sameSite: 'strict',
|
||||
expires: new Date(session.expire),
|
||||
secure: true,
|
||||
path: '/'
|
||||
});
|
||||
|
||||
// Redirect to the account page.
|
||||
throw redirect(301, '/account');
|
||||
}
|
||||
};
|
||||
```
|
||||
@@ -0,0 +1,65 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Create account page
|
||||
description: Add Authentication to a SvelteKit project using Appwrite.
|
||||
step: 6
|
||||
---
|
||||
|
||||
Now the end-user is able to sign in, we can create the account page. This page will display basic information about the user, and allow the user to log out. Create a new file in the `src/routes/account` directory called `+page.server.js` and add the following code:
|
||||
|
||||
```js
|
||||
// src/routes/account/+page.server.js
|
||||
import { SESSION_COOKIE, createAppwriteClient } from '$lib/server/appwrite.js';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
|
||||
export async function load({ locals }) {
|
||||
// Logged out users can't access this page.
|
||||
if (!locals.user) throw redirect(301, '/signin');
|
||||
|
||||
// Pass the stored user local to the page.
|
||||
return {
|
||||
user: locals.user
|
||||
};
|
||||
}
|
||||
|
||||
// Define our log out endpoint/server action.
|
||||
export const actions = {
|
||||
default: async (event) => {
|
||||
// Create the Appwrite client.
|
||||
const { account } = createAppwriteClient(event);
|
||||
|
||||
// Delete the session on Appwrite, and delete the session cookie.
|
||||
await account.deleteSession('current');
|
||||
event.cookies.delete(SESSION_COOKIE);
|
||||
|
||||
// Redirect to the sign in page.
|
||||
throw redirect(301, '/signin');
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Create a new file in the `src/routes/account` directory called `+page.svelte` and add the following code:
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
export let data;
|
||||
|
||||
const { user } = data
|
||||
</script>
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Email:</strong> {user.email}
|
||||
</li>
|
||||
<li>
|
||||
<strong>Name:</strong> {user.name}
|
||||
</li>
|
||||
<li>
|
||||
<strong>ID: </strong> {user.$id}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<form action="/account" method="post">
|
||||
<button type="submit">Log out</button>
|
||||
</form>
|
||||
```
|
||||
@@ -0,0 +1,84 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Adding OAuth2 authentication with SSR
|
||||
description: Add Authentication to a SvelteKit project using Appwrite.
|
||||
step: 7
|
||||
---
|
||||
|
||||
To support the OAuth2 flow, we first redirect the user to the OAuth2 provider, and then handle the callback from the OAuth2 provider.
|
||||
|
||||
To redirect, add a button to our sign in page that redirects the user to the OAuth2 provider.
|
||||
|
||||
```svelte
|
||||
<!-- src/routes/sigin/+page.svelte -->
|
||||
|
||||
<!-- ... existing sign in form -->
|
||||
|
||||
<form action="/oauth2" method="post">
|
||||
<input type="hidden" name="provider" value="github" />
|
||||
<button type="submit">Sign in with GitHub</button>
|
||||
</form>
|
||||
```
|
||||
|
||||
Add a new server route to handle the redirect.
|
||||
|
||||
```js
|
||||
// src/routes/signin/+page.server.js
|
||||
|
||||
// ..
|
||||
|
||||
|
||||
import { SESSION_COOKIE, createAppwriteClient } from '$lib/server/appwrite.js';
|
||||
import { redirect } from '@sveltejs/kit';
|
||||
|
||||
export const actions = {
|
||||
// ... existing actions
|
||||
|
||||
oauth2: async (event) => {
|
||||
const formData = await event.request.formData();
|
||||
const provider = formData.get('provider') ?? 'github';
|
||||
|
||||
const { account } = createAppwriteClient();
|
||||
const redirectURL = account.createOAuth2Token(
|
||||
provider,
|
||||
'<YOUR_WEBSITE_DOMAIN>/oauth2',
|
||||
'<YOUR_WEBSITE_DOMAIN>/signin'
|
||||
);
|
||||
|
||||
throw redirect(url);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
The `createOAuth2Token` method redirects the user to the OAuth2 provider, and then the OAuth2 provider redirects the user back to the `/oauth2` route with the `userId` and `secret` URL query parameters.
|
||||
|
||||
Handle the callback and create a session for the user. Create a new server route at `src/routes/oauth2/+server.js`:
|
||||
|
||||
```js
|
||||
// src/routes/oauth2/+server.js
|
||||
|
||||
import { SESSION_COOKIE, createAppwriteClient } from '$lib/server/appwrite';
|
||||
|
||||
export async function GET(event) {
|
||||
// We should have a `userId` and `secret` query parameters in the URL
|
||||
const userId = event.url.searchParams.get('userId') as string;
|
||||
const secret = event.url.searchParams.get('secret') as string;
|
||||
|
||||
// Exchange the token `userId` and `secret` for a session
|
||||
const { account } = createAppwriteClient(event);
|
||||
const session = await account.createSession(userId, secret);
|
||||
|
||||
// Redirect to the account page, and set the session cookie
|
||||
const headers = new Headers({
|
||||
location: '/account',
|
||||
'set-cookie': event.cookies.serialize(SESSION_COOKIE, session.secret, {
|
||||
sameSite: 'strict',
|
||||
expires: new Date(session.expire),
|
||||
secure: true,
|
||||
path: '/'
|
||||
})
|
||||
});
|
||||
|
||||
return new Response(null, { status: 302, headers });
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,11 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: All set
|
||||
description: Add Authentication to a SvelteKit project using Appwrite.
|
||||
step: 8
|
||||
---
|
||||
If you want to see the complete source code, see the [demos-for-svelte](https://github.com/appwrite/demos-for-svelte/tree/main/server-side-rendering) repository.
|
||||
|
||||
## Other authentication methods
|
||||
Appwrite also supports OAuth, passwordless login, anonymous login, and phone login.
|
||||
Learn more about them in the [authentication guide](https://appwrite.io/docs/products/auth).
|
||||
Reference in New Issue
Block a user