auth added not tested yet
This commit is contained in:
parent
278aa030cb
commit
fc5c2f0eab
17 changed files with 230 additions and 243 deletions
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
|
|
@ -19,8 +19,9 @@ CREATE TABLE "uploads" (
|
|||
--> statement-breakpoint
|
||||
CREATE TABLE "users" (
|
||||
"user_id" text PRIMARY KEY NOT NULL,
|
||||
"paid_status" text NOT NULL,
|
||||
"expires_in" timestamp NOT NULL
|
||||
"paid_status" text,
|
||||
"expires_in" text,
|
||||
"refresh_token" text
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "projects" ADD CONSTRAINT "projects_user_id_users_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("user_id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
4
drizzle/0001_shallow_umar.sql
Normal file
4
drizzle/0001_shallow_umar.sql
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
ALTER TABLE "users" ADD COLUMN "email" text NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "users" ADD COLUMN "last_name" text;--> statement-breakpoint
|
||||
ALTER TABLE "users" ADD COLUMN "first_name" text;--> statement-breakpoint
|
||||
ALTER TABLE "users" ADD COLUMN "image" text;
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
ALTER TABLE "users" ALTER COLUMN "paid_status" DROP NOT NULL;--> statement-breakpoint
|
||||
ALTER TABLE "users" ALTER COLUMN "expires_in" DROP NOT NULL;
|
||||
|
|
@ -1 +0,0 @@
|
|||
ALTER TABLE "users" ALTER COLUMN "expires_in" SET DATA TYPE text;
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"id": "7a9f9e79-63fc-4d2b-8b25-616f96161308",
|
||||
"id": "a0fe5e52-63bf-4a92-adb0-ae296fb9f33e",
|
||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
|
|
@ -156,13 +156,19 @@
|
|||
"name": "paid_status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
"notNull": false
|
||||
},
|
||||
"expires_in": {
|
||||
"name": "expires_in",
|
||||
"type": "timestamp",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
"notNull": false
|
||||
},
|
||||
"refresh_token": {
|
||||
"name": "refresh_token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"id": "5443181c-129a-488a-9001-d65b03b0119f",
|
||||
"prevId": "7a9f9e79-63fc-4d2b-8b25-616f96161308",
|
||||
"id": "b6897b47-e0f0-48c5-8917-696944c8524b",
|
||||
"prevId": "a0fe5e52-63bf-4a92-adb0-ae296fb9f33e",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
|
|
@ -152,6 +152,30 @@
|
|||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"last_name": {
|
||||
"name": "last_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"first_name": {
|
||||
"name": "first_name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"image": {
|
||||
"name": "image",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"paid_status": {
|
||||
"name": "paid_status",
|
||||
"type": "text",
|
||||
|
|
@ -160,7 +184,13 @@
|
|||
},
|
||||
"expires_in": {
|
||||
"name": "expires_in",
|
||||
"type": "timestamp",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"refresh_token": {
|
||||
"name": "refresh_token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,188 +0,0 @@
|
|||
{
|
||||
"id": "88a4eebc-30cb-457f-9fc1-c6bbff735742",
|
||||
"prevId": "5443181c-129a-488a-9001-d65b03b0119f",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
"public.projects": {
|
||||
"name": "projects",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"project_id": {
|
||||
"name": "project_id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"object": {
|
||||
"name": "object",
|
||||
"type": "json",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"description": {
|
||||
"name": "description",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"projects_user_id_users_user_id_fk": {
|
||||
"name": "projects_user_id_users_user_id_fk",
|
||||
"tableFrom": "projects",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
],
|
||||
"columnsTo": [
|
||||
"user_id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.uploads": {
|
||||
"name": "uploads",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "uuid",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "gen_random_uuid()"
|
||||
},
|
||||
"filename": {
|
||||
"name": "filename",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"url": {
|
||||
"name": "url",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"projectId": {
|
||||
"name": "projectId",
|
||||
"type": "uuid",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": false,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"uploads_projectId_projects_project_id_fk": {
|
||||
"name": "uploads_projectId_projects_project_id_fk",
|
||||
"tableFrom": "uploads",
|
||||
"tableTo": "projects",
|
||||
"columnsFrom": [
|
||||
"projectId"
|
||||
],
|
||||
"columnsTo": [
|
||||
"project_id"
|
||||
],
|
||||
"onDelete": "no action",
|
||||
"onUpdate": "no action"
|
||||
}
|
||||
},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.users": {
|
||||
"name": "users",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"user_id": {
|
||||
"name": "user_id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"paid_status": {
|
||||
"name": "paid_status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"expires_in": {
|
||||
"name": "expires_in",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
}
|
||||
},
|
||||
"enums": {},
|
||||
"schemas": {},
|
||||
"sequences": {},
|
||||
"roles": {},
|
||||
"policies": {},
|
||||
"views": {},
|
||||
"_meta": {
|
||||
"columns": {},
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,22 +5,15 @@
|
|||
{
|
||||
"idx": 0,
|
||||
"version": "7",
|
||||
"when": 1737800628545,
|
||||
"tag": "0000_eager_marvel_zombies",
|
||||
"when": 1737876637906,
|
||||
"tag": "0000_tidy_echo",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "7",
|
||||
"when": 1737804031716,
|
||||
"tag": "0001_useful_nighthawk",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 2,
|
||||
"version": "7",
|
||||
"when": 1737806743289,
|
||||
"tag": "0002_broad_eternity",
|
||||
"when": 1737876981144,
|
||||
"tag": "0001_shallow_umar",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -11,12 +11,14 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@clerk/backend": "^1.23.7",
|
||||
"@elysiajs/cookie": "^0.8.0",
|
||||
"@elysiajs/cors": "^1.2.0",
|
||||
"@elysiajs/swagger": "^1.2.0",
|
||||
"dotenv": "^16.4.7",
|
||||
"drizzle-orm": "^0.38.4",
|
||||
"elysia": "latest",
|
||||
"jose": "^5.9.6",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"minio": "^8.0.3",
|
||||
"pg": "^8.13.1",
|
||||
"postgres": "^3.4.5"
|
||||
|
|
|
|||
|
|
@ -4,6 +4,11 @@ import { users } from "../../db/schema";
|
|||
import { db } from "../../db";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
// @ts-ignore
|
||||
import jwt from "jsonwebtoken";
|
||||
|
||||
import { checkUserInDB, createUser, storeRefreshToken } from "../../helper/auth/auth.helper";
|
||||
|
||||
// Initialize Clerk with your API key
|
||||
const clerk = createClerkClient({ secretKey: ENV.CLERK_SECRET_KEY });
|
||||
|
||||
|
|
@ -15,7 +20,18 @@ export const getUserData = async (userId: string) => {
|
|||
]);
|
||||
|
||||
if (user && !checkInDB.found) {
|
||||
const userData = await createUser(user.id);
|
||||
|
||||
// Validate and transform user data
|
||||
const userDBData = {
|
||||
id: user.id,
|
||||
email: user.emailAddresses[0].emailAddress, // Assuming the first email address
|
||||
firstName: user.firstName || "N/A", // Provide a default value if needed
|
||||
lastName: user.lastName || "N/A",
|
||||
image: user.imageUrl,
|
||||
};
|
||||
|
||||
const userData = await createUser(userDBData);
|
||||
|
||||
return { status: 200, message: "User retrieved successfully", data: userData };
|
||||
}
|
||||
if (user && checkInDB.found) {
|
||||
|
|
@ -30,31 +46,6 @@ export const getUserData = async (userId: string) => {
|
|||
}
|
||||
};
|
||||
|
||||
export const checkUserInDB = async (id: string) => {
|
||||
try {
|
||||
const user = await db.select().from(users).where(eq(users.id, id));
|
||||
return { status: 200, found: user?.length > 0 };
|
||||
} catch (error: any) {
|
||||
console.error("Error in checkUserInDB:", error.message || error.toString());
|
||||
return { status: 500, message: `An error occurred while checking the user in DB` };
|
||||
}
|
||||
};
|
||||
|
||||
export const createUser = async (id: string) => {
|
||||
try {
|
||||
const [saveUser] = await db.insert(users).values({ id }).returning({ insertedId: users.id });
|
||||
|
||||
if (!saveUser || !saveUser.insertedId) {
|
||||
throw new Error("Failed to create user or missing insertedId");
|
||||
}
|
||||
|
||||
return { status: 200, message: "User created successfully", data: saveUser.insertedId };
|
||||
} catch (error: any) {
|
||||
console.error("Error in createUser:", error.message || error.toString());
|
||||
return { status: 500, message: `An error occurred while creating the user` };
|
||||
}
|
||||
};
|
||||
|
||||
export const updateUser = async (id: string, body) => {
|
||||
try {
|
||||
const updateUserData = await db.update(users).set({ paid_status: body?.paid_status, expires_in: body?.package_expire_date }).where(eq(users.id, id)).returning({ updatedId: users.id });
|
||||
|
|
@ -65,4 +56,88 @@ export const updateUser = async (id: string, body) => {
|
|||
console.error("Error in updateUser:", error.message || error.toString());
|
||||
return { status: 500, message: `An error occurred while updating the user` };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const generateToken = async (context: any) => {
|
||||
try {
|
||||
const userId = context?.params?.userId;
|
||||
// generating accessToken and refreshToken
|
||||
const user = await checkUserInDB(userId);
|
||||
if (user?.found === true) {
|
||||
const accessSecret = ENV.JWT_ACCESS_TOKEN_SECRET;
|
||||
const refreshSecret = ENV.JWT_REFRESH_TOKEN_SECRET;
|
||||
|
||||
// generate access token
|
||||
const accessToken = jwt.sign({ userId }, accessSecret, { expiresIn: '3h' });
|
||||
|
||||
// generate refresh token
|
||||
const refreshToken = jwt.sign({ userId }, refreshSecret, { expiresIn: '7d' });
|
||||
|
||||
// store refresh token in db
|
||||
const storeRToken = await storeRefreshToken(userId, refreshToken);
|
||||
|
||||
if (storeRToken.status === 200) {
|
||||
context.cookie.access_token = {
|
||||
value: accessToken,
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: 'none',
|
||||
path: "/",
|
||||
maxAge: 3 * 60 * 60 * 1000, // 3 hours
|
||||
}
|
||||
|
||||
return { status: 200, message: "Token generated successfully", token: accessToken };
|
||||
}
|
||||
|
||||
return { status: 500, message: "An error occurred while storing the refresh token" };
|
||||
}
|
||||
else {
|
||||
return { status: 404, message: "Unauthorized!!!" };
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error("Error in generateToken:", error.message || error.toString());
|
||||
return { status: 500, message: `An error occurred while generating the token` };
|
||||
}
|
||||
}
|
||||
|
||||
export const verifyToken = async (context: any) => {
|
||||
try {
|
||||
// if token is in cookie, verify it
|
||||
const token_cookie = context.cookie.access_token.value;
|
||||
if (token_cookie) {
|
||||
const verify_cookie = jwt.verify(token_cookie, ENV.JWT_REFRESH_TOKEN_SECRET);
|
||||
if (verify_cookie) {
|
||||
return { status: 200, message: "Token verified successfully" };
|
||||
}
|
||||
else {
|
||||
return { status: 401, message: "Unauthorized!!!" };
|
||||
}
|
||||
}
|
||||
// if token is not in cookie, then check in header and verify it
|
||||
else {
|
||||
const token_header = context.headers.authorization.split("Bearer ")[1];
|
||||
|
||||
if (token_header) {
|
||||
const verify_header = jwt.decode(token_header);
|
||||
|
||||
if (verify_header?.userId) {
|
||||
context.params.userId = verify_header.userId;
|
||||
await generateToken(context);
|
||||
}
|
||||
else {
|
||||
return { status: 401, message: "Unauthorized!!!" };
|
||||
}
|
||||
}
|
||||
else {
|
||||
return { status: 401, message: "Unauthorized!!!" };
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error: any) {
|
||||
console.log("Error in verifyToken:", error.message || error.toString());
|
||||
return { status: 500, message: `An error occurred while verifying the token` };
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import Elysia from "elysia";
|
||||
import { getUserData, updateUser } from "./auth.controller";
|
||||
import { generateToken, getUserData, updateUser, verifyToken } from "./auth.controller";
|
||||
|
||||
export const authRoute = new Elysia({
|
||||
prefix: "/auth",
|
||||
|
|
@ -9,6 +9,11 @@ export const authRoute = new Elysia({
|
|||
}
|
||||
})
|
||||
|
||||
authRoute.get("/user/:userId", ({ params: { userId } }) => getUserData(userId));
|
||||
authRoute.get("/user/:userId", async ({ params: { userId } }) => await getUserData(userId));
|
||||
|
||||
authRoute.post("/user/update/:userId", async ({ params: { userId }, body }) => await updateUser(userId, body));
|
||||
|
||||
authRoute.get("/generate-token/:userId", async (context) => await generateToken(context));
|
||||
|
||||
authRoute.get("/verify-token", async (context) => await verifyToken(context));
|
||||
|
||||
authRoute.post("/user/update/:userId", ({ params: { userId }, body }) => updateUser(userId, body));
|
||||
|
|
@ -3,13 +3,14 @@ import { projectRoutes } from "./project/project.route";
|
|||
import { uploadRoutes } from "./upload/upload.route";
|
||||
import { verifyAuth } from "../middlewares/auth.middlewares";
|
||||
import { authRoute } from "./auth/auth.route";
|
||||
import cookie from "@elysiajs/cookie";
|
||||
|
||||
export const api = new Elysia({
|
||||
prefix: "/api",
|
||||
});
|
||||
|
||||
// api.derive(verifyAuth);
|
||||
|
||||
api.use(cookie());
|
||||
api.use(authRoute);
|
||||
api.use(projectRoutes);
|
||||
api.use(uploadRoutes);
|
||||
|
|
@ -6,7 +6,10 @@ import cors from "@elysiajs/cors";
|
|||
import { api } from "./api";
|
||||
|
||||
const app = new Elysia()
|
||||
.use(cors())
|
||||
.use(cors({
|
||||
origin: "http://localhost:5175",
|
||||
credentials: true,
|
||||
}))
|
||||
.use(swagger({
|
||||
path: "/docs",
|
||||
documentation: {
|
||||
|
|
|
|||
|
|
@ -9,4 +9,6 @@ export const ENV = {
|
|||
MINIO_ENDPOINT: process.env.MINIO_ENDPOINT,
|
||||
MINIO_PORT: process.env.MINIO_PORT,
|
||||
CLERK_SECRET_KEY: process.env.CLERK_SECRET_KEY,
|
||||
JWT_ACCESS_TOKEN_SECRET: process.env.JWT_ACCESS_TOKEN_SECRET,
|
||||
JWT_REFRESH_TOKEN_SECRET: process.env.JWT_REFRESH_TOKEN_SECRET,
|
||||
}
|
||||
|
|
@ -2,8 +2,13 @@ import { json, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
|
|||
|
||||
export const users = pgTable("users", {
|
||||
id: text("user_id").primaryKey().notNull(),
|
||||
email: text("email").notNull(),
|
||||
lastName: text("last_name"),
|
||||
firstName: text("first_name"),
|
||||
image: text("image"),
|
||||
paid_status: text("paid_status"),
|
||||
expires_in: text("expires_in"),
|
||||
refresh_token: text("refresh_token"),
|
||||
});
|
||||
|
||||
export const projects = pgTable("projects", {
|
||||
|
|
|
|||
51
src/helper/auth/auth.helper.ts
Normal file
51
src/helper/auth/auth.helper.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import { eq } from "drizzle-orm";
|
||||
import { db } from "../../db";
|
||||
import { users } from "../../db/schema";
|
||||
|
||||
type User = {
|
||||
id: string;
|
||||
email: string;
|
||||
lastName: string;
|
||||
firstName: string;
|
||||
image: string;
|
||||
}
|
||||
|
||||
// this will check the user into our local canvas database
|
||||
export const checkUserInDB = async (id: string) => {
|
||||
try {
|
||||
const user = await db.select().from(users).where(eq(users.id, id));
|
||||
return { status: 200, found: user?.length > 0 };
|
||||
} catch (error: any) {
|
||||
console.error("Error in checkUserInDB:", error.message || error.toString());
|
||||
return { status: 500, message: `An error occurred while checking the user in DB` };
|
||||
}
|
||||
};
|
||||
|
||||
export const createUser = async (body: User) => {
|
||||
try {
|
||||
const { id, email, lastName, firstName, image } = body;
|
||||
|
||||
const [saveUser] = await db.insert(users).values({ id, email, lastName, firstName, image }).returning({ insertedId: users.id });
|
||||
|
||||
if (!saveUser || !saveUser.insertedId) {
|
||||
throw new Error("Failed to create user or missing insertedId");
|
||||
}
|
||||
|
||||
return { status: 200, message: "User created successfully", data: saveUser.insertedId };
|
||||
} catch (error: any) {
|
||||
console.error("Error in createUser:", error.message || error.toString());
|
||||
return { status: 500, message: `An error occurred while creating the user` };
|
||||
}
|
||||
};
|
||||
|
||||
// this will store the refresh token in the database
|
||||
export const storeRefreshToken = async (userId: string, refreshToken: string) => {
|
||||
try {
|
||||
// store refresh token in db
|
||||
const storeRToken = await db.update(users).set({ refresh_token: refreshToken }).where(eq(users.id, userId)).returning({ updatedId: users.id });
|
||||
return { status: 200, message: "Refresh token stored successfully" };
|
||||
} catch (error: any) {
|
||||
console.error("Error in storeRToken:", error.message || error.toString());
|
||||
return { status: 500, message: `An error occurred while storing the refresh token` }
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue