Skip to content

Commit

Permalink
Merge pull request #21 from wpsadi/appwrite-auth
Browse files Browse the repository at this point in the history
Appwrite auth
  • Loading branch information
aayank13 authored Nov 19, 2024
2 parents 2b49f99 + 7715f71 commit 1eef3f5
Show file tree
Hide file tree
Showing 15 changed files with 176 additions and 26 deletions.
7 changes: 6 additions & 1 deletion .env.sample
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# Appwrite
APPWRITE_PROJECT_ID = "5f5f3d5d5f5f3"
APPWRITE_ENDPOINT = "https://appwrite.io/v1"
APPWRITE_KEY = "G"
APPWRITE_KEY = "G"


# Vercel
HTTPS = 1 # 0 for http, 1 for https
VERCEL_URL = localhost:3000
4 changes: 1 addition & 3 deletions app/api/auth/login/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,9 @@ export async function POST(req: NextRequest) {
);



const sessionKey = session.secret;

// setting the cookie
await SetAuthCookie(sessionKey);
await SetAuthCookie(session);


const {account:SavedUserAccount} = await ClientAW();
Expand Down
13 changes: 13 additions & 0 deletions app/api/auth/logout/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ClientAW } from "@/appwrite_configs/config";

import { errorHandler, successHandler } from "../../handler";

export async function POST() {
try {
const { account } = await ClientAW(true);
await account.deleteSession("current");
return successHandler({}, "Logged out successfully", 200);
} catch (e) {
return errorHandler(e);
}
}
5 changes: 3 additions & 2 deletions app/api/auth/oauth/github/login/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import * as sdk from "node-appwrite";

import { errorHandler } from "@/app/api/handler";
import { ClientAW } from "@/appwrite_configs/config";
import { env } from "@/env";

export async function GET() {
try {
const { account } = await ClientAW(false);
const result = await account.createOAuth2Token(
sdk.OAuthProvider.Github, // provider
"http://localhost:3000/api/auth/oauth/github/login/success", // success (optional)
"http://localhost:3000/api/auth/oauth/github/login/failure", // failure (optional)
`${env.vercel.url}/auth/oauth/github/login/success`, // success (optional)
`${env.vercel.url}/auth/oauth/github/login/failure`, // failure (optional)
[] // scopes (optional)
);

Expand Down
3 changes: 1 addition & 2 deletions app/api/auth/oauth/github/login/success/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ export async function GET(req: NextRequest) {
const { account: accountRoot } = await RootAW();
const session = await accountRoot.createSession(userId, secret);

const sessionKey = session.secret;

// setting the cookie
await SetAuthCookie(sessionKey);
await SetAuthCookie(session);

const { account: SavedUserAccount } = await ClientAW();

Expand Down
5 changes: 3 additions & 2 deletions app/api/auth/oauth/github/register/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ import * as sdk from "node-appwrite";

import { errorHandler } from "@/app/api/handler";
import { ClientAW } from "@/appwrite_configs/config";
import { env } from "@/env";

export async function GET() {
try {
const { account } = await ClientAW(false);
const result = await account.createOAuth2Token(
sdk.OAuthProvider.Github, // provider
"http://localhost:3000/api/auth/oauth/github/register/success", // success (optional)
"http://localhost:3000/api/auth/oauth/github/register/failure", // failure (optional)
`${env.vercel.url}/auth/oauth/github/register/success`, // success (optional)
`${env.vercel.url}/auth/oauth/github/register/failure`, // failure (optional)
[] // scopes (optional)
);

Expand Down
3 changes: 1 addition & 2 deletions app/api/auth/oauth/github/register/success/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@ export async function GET(req: NextRequest) {
const { account: accountRoot } = await RootAW();
const session = await accountRoot.createSession(userId, secret);

const sessionKey = session.secret;

// setting the cookie
await SetAuthCookie(sessionKey);
await SetAuthCookie(session);

const { account: SavedUserAccount } = await ClientAW();

Expand Down
20 changes: 11 additions & 9 deletions app/api/auth/register/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type { NextRequest } from "next/server";
import { AppwriteException, ID } from "node-appwrite";

import { ClientAW, RootAW } from "@/appwrite_configs/config";
import { env } from "@/env";
import { SetAuthCookie } from "@/helpers/sessionCookieFunctions";
import { registerSchema } from "@/validations/auth/registerSchema";

Expand All @@ -10,12 +11,12 @@ import { errorHandler, successHandler } from "../../handler";
export async function POST(req: NextRequest) {
try {
let body = {};
try{
body = await req.json() || {};
}catch{
try {
body = (await req.json()) || {};
} catch {
throw new AppwriteException("No body passed", 400);
}

const validation = await registerSchema.safeParse(body);
if (!validation.success) {
throw new AppwriteException(validation.error.errors[0].message, 400);
Expand All @@ -39,14 +40,16 @@ export async function POST(req: NextRequest) {
validatedData.email,
validatedData.password
);
const sessionKey = session.secret;


// setting the cookie
await SetAuthCookie(sessionKey);
await SetAuthCookie(session);

const { account: SavedUserAccount } = await ClientAW();
// sending email
await SavedUserAccount.createVerification("http://localhost:3000/api/user/email/verify");
await SavedUserAccount.createVerification(
`${env.vercel.url}/user/email/verify`
);

// return the user
return successHandler({
Expand All @@ -56,10 +59,9 @@ export async function POST(req: NextRequest) {
name: user.name,
verified: user.emailVerification,
registrationDate: user.registration,
}
},
});
} catch (e) {
return errorHandler(e);
}
}

3 changes: 2 additions & 1 deletion app/api/user/email/verify/resend/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AppwriteException } from "node-appwrite";

import { errorHandler, successHandler } from "@/app/api/handler";
import { ClientAW } from "@/appwrite_configs/config";
import { env } from "@/env";

export async function POST(req: NextRequest) {
try {
Expand Down Expand Up @@ -32,7 +33,7 @@ export async function POST(req: NextRequest) {
throw new AppwriteException("User Id does not match", 400);
}

await account.createVerification("http://localhost:3000/api/user/email/verify");
await account.createVerification(`${env.vercel.url}/user/email/verify`);

return successHandler(
{},
Expand Down
55 changes: 55 additions & 0 deletions app/api/user/recovery/password/confirm/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import type { NextRequest } from "next/server";
import { AppwriteException } from "node-appwrite";

import { errorHandler, successHandler } from "@/app/api/handler";
import { ClientAW } from "@/appwrite_configs/config";
import { recoveryPasswordConfirmSchema } from "@/validations/user/recoveryPasswordConfirm";

export async function POST(req: NextRequest) {
try {
const queryStore = req.nextUrl.searchParams;

const isPresent = queryStore.has("secret") && queryStore.has("userId");

if (!isPresent) {
return errorHandler(
new AppwriteException("userId or secret not present", 400)
);
}

const secret = queryStore.get("secret") as string;
const userId = queryStore.get("userId") as string;

// getting new password
let body = {
userId: null,
};
try {
body = await req.json();
} catch {
throw new AppwriteException("No body passed", 400);
}

const validation = recoveryPasswordConfirmSchema.safeParse(body);

if (!validation.success) {
throw new AppwriteException(validation.error.errors[0].message, 400);
}

const validatedData = validation.data;

const { account } = await ClientAW(false);

await account.updateRecovery(userId, secret,validatedData.newPassword);

return successHandler(
{
id: userId,
},
"Passwrord reset successfully",
201
);
} catch (e) {
return errorHandler(e);
}
}
34 changes: 34 additions & 0 deletions app/api/user/recovery/password/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { NextRequest } from "next/server";
import { AppwriteException } from "node-appwrite";

import { errorHandler, successHandler } from "@/app/api/handler";
import { ClientAW } from "@/appwrite_configs/config";
import { recoveryPasswordSchema } from "@/validations/user/recoveryPassword";

export async function POST(req: NextRequest) {
try {
let body = {};
try {
body = (await req.json()) || {};
} catch {
throw new AppwriteException("No body passed", 400);
}

const validation = recoveryPasswordSchema.safeParse(body);
if (!validation.success) {
throw new AppwriteException(validation.error.errors[0].message, 400);
}

const { account } = await ClientAW(true);

const validatedData = validation.data;
await account.createRecovery(
validatedData.email,
"http://localhost:3000/api/user/recovery/password/confirm"
);

return successHandler({}, "Recovery email sent successfully", 201);
} catch (e) {
return errorHandler(e);
}
}
13 changes: 13 additions & 0 deletions app/api/user/sessions/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { ClientAW } from "@/appwrite_configs/config";

import { errorHandler, successHandler } from "../../handler";

export async function GET() {
try {
const { account } = await ClientAW(true);
const listSessions = await account.listSessions();
return successHandler(listSessions, "Sessions fetched successfully", 200);
} catch (e) {
return errorHandler(e);
}
}
8 changes: 4 additions & 4 deletions helpers/sessionCookieFunctions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ReadonlyRequestCookies } from "next/dist/server/web/spec-extension/adapters/request-cookies";
import { cookies } from "next/headers";
import { AppwriteException } from "node-appwrite";
import { AppwriteException, Models } from "node-appwrite";

import { env } from "@/env";

Expand All @@ -21,13 +21,13 @@ export const RetrieveAuthCookie = async ():Promise<string> => {
};


export const SetAuthCookie = async (cookieValue: string) => {
export const SetAuthCookie = async (cookieData:Models.Session) => {
const cookieStore = await cookies();
cookieStore.set(env.auth.cookieName, cookieValue, {
cookieStore.set(env.auth.cookieName, cookieData.secret, {
httpOnly:env.auth.cookieHttpOnly,
secure:env.auth.cookieSecure,
sameSite:env.auth.cookieSameSite ,
path:env.auth.cookiePath,
maxAge:env.auth.cookieMaxAge
expires:new Date(cookieData.expire)
})
}
10 changes: 10 additions & 0 deletions validations/user/recoveryPassword.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { z } from "zod";

export const recoveryPasswordSchema = z.object({
email: z
.string({
required_error: "Email is required",
invalid_type_error: "Email must be a string",
})
.email({message: "Invalid email"}),
})
19 changes: 19 additions & 0 deletions validations/user/recoveryPasswordConfirm.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { z } from "zod";

export const recoveryPasswordConfirmSchema = z.object({
newPassword: z
.string({
required_error: "New password is required",
invalid_type_error: "New password must be a string",
})
.min(6, {message: "New password must be at least 6 characters long"}),
confirmPassword: z
.string({
required_error: "Confirm password is required",
invalid_type_error: "Confirm password must be a string",
})
.min(6, {message: "Confirm password must be at least 6 characters long"}),
}).refine(data => data.newPassword === data.confirmPassword, {
message: "New password and confirm password must match",
path: ["confirmPassword"],
});

0 comments on commit 1eef3f5

Please sign in to comment.