mirror of
https://github.com/LukeHagar/website.git
synced 2025-12-09 21:07:46 +00:00
feat: nuxt ssr auth tutorial
This commit is contained in:
10
src/routes/docs/tutorials/nuxt-ssr-auth/+layout.svelte
Normal file
10
src/routes/docs/tutorials/nuxt-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/nuxt-ssr-auth/+layout.ts
Normal file
11
src/routes/docs/tutorials/nuxt-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/nuxt-ssr-auth/+page.ts
Normal file
6
src/routes/docs/tutorials/nuxt-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/nuxt-ssr-auth/step-1');
|
||||
};
|
||||
20
src/routes/docs/tutorials/nuxt-ssr-auth/step-1/+page.markdoc
Normal file
20
src/routes/docs/tutorials/nuxt-ssr-auth/step-1/+page.markdoc
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Server-side authentication with Nuxt
|
||||
description: Add SSR authentication to your Nuxt app with Appwrite
|
||||
step: 1
|
||||
difficulty: beginner
|
||||
readtime: 20
|
||||
framework: Nuxt
|
||||
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.
|
||||
This tutorials shows how Appwrite can help you add authentication to your Nuxt app using server-side rendering (SSR).
|
||||
|
||||
# Before you start {% #before-you-start %}
|
||||
|
||||
Even if you've never tried Appwrite, you will get an idea of what it'll feel like to build with Vue and Appwrite.
|
||||
|
||||
If you're inspired and wish to follow along, make sure you've followed [Start with Nuxt](https://appwrite.io/docs/quick-starts/nuxt) first.
|
||||
Clone the [demos-for-vue](https://github.com/appwrite/demos-for-vue) examples and follow along with the source code.
|
||||
39
src/routes/docs/tutorials/nuxt-ssr-auth/step-2/+page.markdoc
Normal file
39
src/routes/docs/tutorials/nuxt-ssr-auth/step-2/+page.markdoc
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Create project
|
||||
description: Add authentication to a Nuxt project using Appwrite.
|
||||
step: 2
|
||||
---
|
||||
|
||||
|
||||
Create a Vue project using [Nuxt](https://nuxt.com/docs/getting-started/installation#new-project).
|
||||
|
||||
```sh
|
||||
npx nuxi@latest init my-nuxt-project
|
||||
```
|
||||
|
||||
The command will give you a prompt with several options/
|
||||
|
||||
The prompt will be something similar to this.
|
||||
|
||||
```sh
|
||||
❯ Which package manager would you like to use?
|
||||
● npm
|
||||
❯ Initialize git repository?
|
||||
● Yes
|
||||
```
|
||||
|
||||
After the prompt is finished, you can head over to the newly create project.
|
||||
|
||||
```sh
|
||||
cd my-nuxt-project
|
||||
```
|
||||
|
||||
# Adding `node-appwrite` to your Vue app
|
||||
|
||||
Appwrite provides a Node SDK that can be used in your Nuxt 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/nuxt)
|
||||
|
||||
```sh
|
||||
npm install node-appwrite
|
||||
```
|
||||
73
src/routes/docs/tutorials/nuxt-ssr-auth/step-3/+page.markdoc
Normal file
73
src/routes/docs/tutorials/nuxt-ssr-auth/step-3/+page.markdoc
Normal file
@@ -0,0 +1,73 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Initialize SDK
|
||||
description: Add authentication to a Nuxt 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.
|
||||
|
||||
{% info title="Appwrite client security" %}
|
||||
We recommend creating a new instance of the Appwrite client for each request. This ensures that the client is not shared between requests and that the session is not shared between users.
|
||||
{% /info %}
|
||||
|
||||
```js
|
||||
// server/lib/appwrite.js
|
||||
import { Client, Account } from "node-appwrite";
|
||||
|
||||
export const SESSION_COOKIE = "my-custom-session";
|
||||
|
||||
export function createAppwriteClient(event) {
|
||||
const config = useRuntimeConfig(event);
|
||||
|
||||
const client = new Client()
|
||||
.setEndpoint(config.public.appwriteEndpoint)
|
||||
.setProject(config.public.appwriteProjectId);
|
||||
|
||||
client.setKey(config.appwriteApiKey);
|
||||
|
||||
const session = getCookie(event, SESSION_COOKIE);
|
||||
if (session) {
|
||||
client.setSession(session);
|
||||
}
|
||||
|
||||
return {
|
||||
get account() {
|
||||
return new Account(client);
|
||||
},
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
`config.appwriteApiKey`, `config.public.appwriteEndpoint` and `config.public.appwriteProjectId` are Nuxt runtime configuration variables. Create a [nuxt.config.js](https://nuxt.com/docs/api/configuration/nuxt-config) file in the root of your project and add the following code to set the runtime configuration.
|
||||
|
||||
```js
|
||||
export default defineNuxtConfig({
|
||||
runtimeConfig: {
|
||||
appwriteKey: process.env.APPWRITE_KEY,
|
||||
public: {
|
||||
appwriteEndpoint: process.env.PUBLIC_APPWRITE_ENDPOINT,
|
||||
appwriteProjectId: process.env.PUBLIC_APPWRITE_PROJECT_ID,
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Now you can use `.env` files to set the environment variables for your project. Retrieve the values for these variables from the Appwrite console. The `PUBLIC_APPWRITE_ENDPOINT` and `PUBLIC_APPWRITE_PROJECT_ID` are the endpoint and project ID for your Appwrite project. The `APPWRITE_KEY` is the API key for your Appwrite project.
|
||||
|
||||
For this tutorial you'll need an API key with the following scopes:
|
||||
- `accounts.read`
|
||||
- `accounts.write`
|
||||
- `sessions.read`
|
||||
- `sessions.write`
|
||||
|
||||
For example, your `.env` might look something similar to this.
|
||||
```text
|
||||
APPWRITE_KEY=<YOUR_APPWRITE_KEY>
|
||||
PUBLIC_APPWRITE_ENDPOINT=https://cloud.appwrite.io/v1
|
||||
PUBLIC_APPWRITE_PROJECT_ID=<YOUR_APPWRITE_PROJECT_ID>
|
||||
```
|
||||
48
src/routes/docs/tutorials/nuxt-ssr-auth/step-4/+page.markdoc
Normal file
48
src/routes/docs/tutorials/nuxt-ssr-auth/step-4/+page.markdoc
Normal file
@@ -0,0 +1,48 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Add server middleware
|
||||
description: Add authentication to a Nuxt project using Appwrite.
|
||||
step: 4
|
||||
---
|
||||
|
||||
Nuxt server middle are functions that run on the server before a route is displayed to the user. Nuxt context allows you to store data for the lifecycle of 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 `server/middleware` directory called `auth.js`:
|
||||
```js
|
||||
// server/middleware/auth.js
|
||||
import { createAppwriteClient } from "../lib/appwrite";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const { account } = createAppwriteClient(event);
|
||||
|
||||
try {
|
||||
event.context.user = await account.get();
|
||||
} catch (error) {}
|
||||
});
|
||||
```
|
||||
|
||||
To ensure the `context` 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";
|
||||
|
||||
declare module "h3" {
|
||||
interface H3EventContext {
|
||||
user?: Models.User<Models.Preferences<any>>;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now, use the `context` object in the home page to redirect based on the user's login status. Create a new file in the `server/routes` directory called `index.js`:
|
||||
|
||||
```js
|
||||
export default defineEventHandler(async (event) => {
|
||||
if (event.context.user) {
|
||||
await sendRedirect(event, "/account");
|
||||
}
|
||||
|
||||
await sendRedirect(event, "/signin");
|
||||
});
|
||||
```
|
||||
|
||||
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.
|
||||
56
src/routes/docs/tutorials/nuxt-ssr-auth/step-5/+page.markdoc
Normal file
56
src/routes/docs/tutorials/nuxt-ssr-auth/step-5/+page.markdoc
Normal file
@@ -0,0 +1,56 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Create sign in page
|
||||
description: Add authentication to a Nuxt project using Appwrite.
|
||||
step: 5
|
||||
---
|
||||
|
||||
We can now implement our sign in page. Create a `signin.vue` file in the `pages` directory:
|
||||
|
||||
```vue
|
||||
<!-- pages/signin.vue -->
|
||||
<template>
|
||||
<form method="post" action="/api/signin">
|
||||
<input id="email" name="email" placeholder="Email" type="email" />
|
||||
<input
|
||||
id="password"
|
||||
name="password"
|
||||
placeholder="Password"
|
||||
type="password"
|
||||
/>
|
||||
<button type="submit">Sign in</button>
|
||||
</form>
|
||||
</template>
|
||||
```
|
||||
|
||||
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 Nuxt form actions we create a `signin.post.js` file in the `server/api` directory:
|
||||
|
||||
```javascript
|
||||
// server/api/signin.post.js
|
||||
import { SESSION_COOKIE, createAppwriteClient } from "~/server/lib/appwrite";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
// Extract the form data
|
||||
const formData = await readFormData(event);
|
||||
const email = formData.get("email") as string;
|
||||
const password = formData.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
|
||||
setCookie(event, SESSION_COOKIE, session.secret, {
|
||||
expires: new Date(session.expire),
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: "strict",
|
||||
});
|
||||
|
||||
// Redirect to the account page.
|
||||
await sendRedirect(event, "/account");
|
||||
});
|
||||
```
|
||||
49
src/routes/docs/tutorials/nuxt-ssr-auth/step-6/+page.markdoc
Normal file
49
src/routes/docs/tutorials/nuxt-ssr-auth/step-6/+page.markdoc
Normal file
@@ -0,0 +1,49 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Create account page
|
||||
description: Add authentication to a Nuxt 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 `pages` directory called `account.vue` and add the following code:
|
||||
|
||||
```vue
|
||||
<!-- pages/account.vue -->
|
||||
<script setup>
|
||||
const { context } = useEvent();
|
||||
const { user } = context;
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>Email:</strong> {{ user.email }}
|
||||
</li>
|
||||
<li>
|
||||
<strong>Name:</strong> {{ user.name }}
|
||||
</li>
|
||||
<li>
|
||||
<strong>ID: </strong> {{ user.$id }}
|
||||
</li>
|
||||
</ul>
|
||||
<form method="post" action="/api/signout">
|
||||
<button type="submit">Log out</button>
|
||||
</form>
|
||||
</template>
|
||||
```
|
||||
|
||||
This page will display the user's email, name, and ID. It also contains a form that will log the user out when submitted. The form will send a `POST` request to the `/api/signout` endpoint. We need to create this endpoint in the server. Create a new file in the `server/routes/api` directory called `signout.post.js` and add the following code:
|
||||
|
||||
```javascript
|
||||
// server/routes/api/signout.post.js
|
||||
import { SESSION_COOKIE, createAppwriteClient } from "~/server/lib/appwrite";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const { account } = createAppwriteClient(event);
|
||||
|
||||
await account.deleteSession("current");
|
||||
deleteCookie(event, SESSION_COOKIE);
|
||||
|
||||
await sendRedirect(event, "/signin");
|
||||
});
|
||||
```
|
||||
78
src/routes/docs/tutorials/nuxt-ssr-auth/step-7/+page.markdoc
Normal file
78
src/routes/docs/tutorials/nuxt-ssr-auth/step-7/+page.markdoc
Normal file
@@ -0,0 +1,78 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: Adding OAuth2 authentication with SSR
|
||||
description: Add authentication to a Nuxt 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.
|
||||
|
||||
```vue
|
||||
<!-- pages/signin.vue -->
|
||||
|
||||
<!-- ... existing sign in form -->
|
||||
|
||||
<form action="/api/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
|
||||
// server/routes/api/oauth2.post.js
|
||||
import { createAppwriteClient } from "~/server/lib/appwrite";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const config = useRuntimeConfig(event);
|
||||
const { account } = createAppwriteClient(event);
|
||||
|
||||
const redirectUrl = await account.createOAuth2Token(
|
||||
"github", // OAuth2 provider
|
||||
`${config.public.appwriteEndpoint}/api/oauth2`, // Success URL: redirect back to the /oauth2 route
|
||||
`${config.public.appwriteEndpoint}/signin` // Failure URL: redirect to the sign in page
|
||||
);
|
||||
|
||||
// Redirect the user to the OAuth2 provider authorization page
|
||||
await sendRedirect(event, redirectUrl);
|
||||
});
|
||||
```
|
||||
|
||||
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 `server/routes/api/oauth2.get.js`.
|
||||
|
||||
```js
|
||||
// server/routes/api/oauth2.post.js
|
||||
import { SESSION_COOKIE, createAppwriteClient } from "~/server/lib/appwrite";
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
// Extract the userId and secret from the URL query parameters
|
||||
const { userId, secret } = getQuery(event);
|
||||
if (!userId || !secret) {
|
||||
return sendRedirect(event, "/signin");
|
||||
}
|
||||
|
||||
// Create the Appwrite client
|
||||
const { account } = createAppwriteClient(event);
|
||||
|
||||
// Exchange the token userId and secret for a session
|
||||
const session = await account.createSession(userId, secret);
|
||||
|
||||
|
||||
// Set the session cookie
|
||||
setCookie(event, SESSION_COOKIE, session.secret, {
|
||||
expires: new Date(session.expire),
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: "strict",
|
||||
});
|
||||
|
||||
// Redirect the user to the account page
|
||||
await sendRedirect(event, "/account");
|
||||
});
|
||||
```
|
||||
11
src/routes/docs/tutorials/nuxt-ssr-auth/step-8/+page.markdoc
Normal file
11
src/routes/docs/tutorials/nuxt-ssr-auth/step-8/+page.markdoc
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
layout: tutorial
|
||||
title: All set
|
||||
description: Add authentication to a Nuxt project using Appwrite.
|
||||
step: 8
|
||||
---
|
||||
If you want to see the complete source code with styling, see the [demos-for-vue](https://github.com/appwrite/demos-for-vue/tree/main/server-side-rendering) repository.
|
||||
|
||||
# Other authentication methods {% #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