feat: update ssr dx nextjs

This commit is contained in:
loks0n
2024-02-22 16:45:59 +00:00
parent bbc5904e96
commit a70e8b5252
6 changed files with 42 additions and 33 deletions

View File

@@ -23,21 +23,38 @@ Doing so could create security vulnerabilities.
import { Client, Account } from "node-appwrite"; import { Client, Account } from "node-appwrite";
import { parseCookie } from "next/dist/compiled/@edge-runtime/cookies"; import { parseCookie } from "next/dist/compiled/@edge-runtime/cookies";
export const SESSION_COOKIE = "a_session"; // The name of your cookie that will store the session
export const SESSION_COOKIE = "my-custom-session";
export function createAppwriteClient(headers) { // Admin client, used to create new accounts
export function createAdminClient() {
const client = new Client() const client = new Client()
.setEndpoint(process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!) .setEndpoint(import.meta.env.PUBLIC_APPWRITE_ENDPOINT)
.setProject(process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!); .setProject(import.meta.env.PUBLIC_APPWRITE_PROJECT_ID)
.setKey(import.meta.env.APPWRITE_KEY); // Set the API key here!
// Set the API key for the client, bypassing rate limiting and enabling // Return the services you need
client.setKey(process.env.APPWRITE_KEY!); return {
get account() {
return new Account(client);
},
};
}
// Extract the session from cookies and use it for the client // Session client, used to make requests on behalf of the logged in user
const cookies = parseCookie(headers.get("cookie") ?? ""); export function createSessionClient(request) {
const client = new Client()
.setEndpoint(import.meta.env.PUBLIC_APPWRITE_ENDPOINT)
.setProject(import.meta.env.PUBLIC_APPWRITE_PROJECT_ID);
// Get the session cookie from the request and set the session
const cookies = parseCookies(request.headers.get("cookie") ?? "");
const session = cookies.get(SESSION_COOKIE); const session = cookies.get(SESSION_COOKIE);
if (session) client.setSession(session); if (session) {
client.setSession(session);
}
// Return the services you need
return { return {
get account() { get account() {
return new Account(client); return new Account(client);
@@ -64,8 +81,6 @@ For this tutorial you'll need an API key with the following scopes:
| Category {% width=120 %} | Required scopes | Purpose | | Category {% width=120 %} | Required scopes | Purpose |
|-----------|---------------------|---------| |-----------|---------------------|---------|
| Accounts | `accounts.read` | Allows API key to read account information. |
| | `accounts.write` | Allows API key to create, update, and delete account information. |
| Sessions | `sessions.write` | Allows API key to create, update, and delete sessions. | | Sessions | `sessions.write` | Allows API key to create, update, and delete sessions. |
{% only_dark %} {% only_dark %}

View File

@@ -14,22 +14,19 @@ Edit the `src/server/appwrite.js` file to create a new function called `getLogge
export async function getLoggedInUser(account) { export async function getLoggedInUser(account) {
try { try {
return await account.get(); return await account.get();
} catch { } catch {}
return undefined;
}
} }
``` ```
Now, use the `getLoggedInUser` function in the home page to redirect based on the user's login status. Create a new file in the `app` directory called `+page.jsx`. Now, use the `getLoggedInUser` function in the home page to redirect based on the user's login status. Create a new file in the `app` directory called `+page.jsx`.
```js ```js
import { createAppwriteClient, getLoggedInUser } from "@/lib/server/appwrite"; import { createSessionClient, getLoggedInUser } from "@/lib/server/appwrite";
import { headers } from "next/headers"; import { headers } from "next/headers";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
export default async function Home() { export default async function Home() {
const { account } = createAppwriteClient(headers()); const { account } = createSessionClient(headers());
const user = await getLoggedInUser(account); const user = await getLoggedInUser(account);
if (!user) redirect("/signin"); if (!user) redirect("/signin");

View File

@@ -11,13 +11,12 @@ We can now implement our sign in page. Create a `+page.jsx` file in the `src/app
// src/app/sigin/+page.jsx // src/app/sigin/+page.jsx
import { import {
createAppwriteClient, createSessionClient,
getLoggedInUser, getLoggedInUser,
} from "@/lib/server/appwrite"; } from "@/lib/server/appwrite";
export default async function SignInPage() { export default async function SignInPage() {
const { account } = createAppwriteClient(headers()); const { account } = createSessionClient(headers());
const user = await getLoggedInUser(account); const user = await getLoggedInUser(account);
if (user) redirect("/account"); if (user) redirect("/account");
@@ -53,7 +52,7 @@ This is an HTML form with an email and password input. When the form is submitte
// previous imports ... // previous imports ...
import { SESSION_COOKIE } from "@/lib/server/appwrite"; import { SESSION_COOKIE, createAdminClient } from "@/lib/server/appwrite";
import { cookies, headers } from "next/headers"; import { cookies, headers } from "next/headers";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
@@ -65,7 +64,7 @@ async function signInWithEmail(formData) {
const email = formData.get("email"); const email = formData.get("email");
const password = formData.get("password"); const password = formData.get("password");
const { account } = createAppwriteClient(headers()); const { account } = createAdminClient();
const session = await account.createEmailPasswordSession(email, password); const session = await account.createEmailPasswordSession(email, password);
@@ -80,4 +79,4 @@ async function signInWithEmail(formData) {
} }
``` ```
The `signInWithEmail` function is an async function that takes the form data as an argument. It uses the `createAppwriteClient` function to create an Appwrite client and then calls the `createEmailPasswordSession` method on the `account` object. This method takes the email and password as arguments and returns a session object. We then set the session secret in a cookie and redirect the user to the account page. The `signInWithEmail` function is an async function that takes the form data as an argument. It uses the `createAdminClient` function to create an admin Appwrite client and then calls the `createEmailPasswordSession` method on the `account` object. This method takes the email and password as arguments and returns a session object. We then set the session secret in a cookie and redirect the user to the account page.

View File

@@ -11,7 +11,7 @@ Now the end-user is able to sign in, we can create the account page. This page w
// src/app/account/page.jsx // src/app/account/page.jsx
import { import {
SESSION_COOKIE, SESSION_COOKIE,
createAppwriteClient, createSessionClient,
getLoggedInUser, getLoggedInUser,
} from "@/lib/server/appwrite"; } from "@/lib/server/appwrite";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
@@ -20,7 +20,7 @@ import { cookies, headers } from "next/headers";
async function signOut() { async function signOut() {
"use server"; "use server";
const { account } = createAppwriteClient(headers()); const { account } = createSessionClient(headers());
cookies().delete(SESSION_COOKIE); cookies().delete(SESSION_COOKIE);
await account.deleteSession("current"); await account.deleteSession("current");
@@ -29,7 +29,7 @@ async function signOut() {
} }
export default async function HomePage() { export default async function HomePage() {
const { account } = createAppwriteClient(headers()); const { account } = createSessionClient(headers());
const user = await getLoggedInUser(account); const user = await getLoggedInUser(account);
if (!user) redirect("/signin"); if (!user) redirect("/signin");

View File

@@ -12,7 +12,7 @@ Add a new server action. Navigate to `src/lib/server` and create a new file `oau
```js ```js
// src/lib/server/oauth2.js // src/lib/server/oauth2.js
import { SESSION_COOKIE, createAppwriteClient } from "@/lib/server/appwrite"; import { SESSION_COOKIE, createAdminClient } from "@/lib/server/appwrite";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
async function signInWithGithub(formData) { async function signInWithGithub(formData) {
@@ -20,7 +20,7 @@ async function signInWithGithub(formData) {
const provider = formData.get('provider') ?? 'github'; const provider = formData.get('provider') ?? 'github';
const { account } = createAppwriteClient(); const { account } = createAdminClient();
const redirectURL = await account.createOAuth2Token( const redirectURL = await account.createOAuth2Token(
provider, provider,
'<YOUR_WEBSITE_DOMAIN>/oauth2', '<YOUR_WEBSITE_DOMAIN>/oauth2',
@@ -53,7 +53,7 @@ Handle the callback and create a session for the user. Create a new Next.js serv
```js ```js
// src/app/oauth2/route.js // src/app/oauth2/route.js
import { SESSION_COOKIE, createAppwriteClient } from "@/lib/server/appwrite"; import { SESSION_COOKIE, createAdminClient } from "@/lib/server/appwrite";
import { cookies } from "next/headers"; import { cookies } from "next/headers";
import { NextResponse } from "next/server"; import { NextResponse } from "next/server";
@@ -61,7 +61,7 @@ export async function GET(request) {
const userId = request.nextUrl.searchParams.get("userId"); const userId = request.nextUrl.searchParams.get("userId");
const secret = request.nextUrl.searchParams.get("secret"); const secret = request.nextUrl.searchParams.get("secret");
const { account } = createAppwriteClient(request.headers); const { account } = createAdminClient();
const session = await account.createSession(userId, secret); const session = await account.createSession(userId, secret);
cookies().set(SESSION_COOKIE, session.secret, { cookies().set(SESSION_COOKIE, session.secret, {

View File

@@ -71,8 +71,6 @@ For this tutorial you'll need an API key with the following scopes:
| Category {% width=120 %} | Required scopes | Purpose | | Category {% width=120 %} | Required scopes | Purpose |
|-----------|---------------------|---------| |-----------|---------------------|---------|
| Accounts | `accounts.read` | Allows API key to read account information. |
| | `accounts.write` | Allows API key to create, update, and delete account information. |
| Sessions | `sessions.write` | Allows API key to create, update, and delete sessions. | | Sessions | `sessions.write` | Allows API key to create, update, and delete sessions. |
{% only_dark %} {% only_dark %}