Refresh Token 구현 변경

This commit is contained in:
static
2024-12-28 15:44:30 +09:00
parent 796e4a7831
commit 1d0c309878
11 changed files with 233 additions and 79 deletions

View File

@@ -1,21 +1,37 @@
import { error } from "@sveltejs/kit";
import argon2 from "argon2";
import { v4 as uuidv4 } from "uuid";
import { getClientByPubKey } from "$lib/server/db/client";
import { getUserByEmail, revokeToken, isTokenRevoked } from "$lib/server/db/user";
import { getUserByEmail } from "$lib/server/db/user";
import {
getRefreshToken,
registerRefreshToken,
rotateRefreshToken,
revokeRefreshToken,
} from "$lib/server/db/token";
import { issueToken, verifyToken, TokenError } from "$lib/server/modules/auth";
const verifyPassword = async (hash: string, password: string) => {
return await argon2.verify(hash, password);
};
const issueAccessToken = (userId: number, clientId?: number) => {
return issueToken({ type: "access", userId, clientId });
};
const issueRefreshToken = async (userId: number, clientId?: number) => {
const jti = uuidv4();
const token = issueToken({ type: "refresh", jti });
if (!(await registerRefreshToken(userId, clientId ?? null, jti))) {
error(403, "Already logged in");
}
return token;
};
export const login = async (email: string, password: string, pubKey?: string) => {
const user = await getUserByEmail(email);
if (!user) {
error(401, "Invalid email or password");
}
const isValid = await verifyPassword(user.password, password);
if (!isValid) {
if (!user || !(await verifyPassword(user.password, password))) {
error(401, "Invalid email or password");
}
@@ -25,36 +41,45 @@ export const login = async (email: string, password: string, pubKey?: string) =>
}
return {
accessToken: issueToken("access", user.id, client?.id),
refreshToken: issueToken("refresh", user.id, client?.id),
accessToken: issueAccessToken(user.id, client?.id),
refreshToken: await issueRefreshToken(user.id, client?.id),
};
};
const verifyRefreshToken = async (refreshToken: string) => {
const tokenData = verifyToken(refreshToken);
if (tokenData === TokenError.EXPIRED) {
error(401, "Token expired");
} else if (
tokenData === TokenError.INVALID ||
tokenData.type !== "refresh" ||
(await isTokenRevoked(refreshToken))
) {
error(401, "Invalid token");
const tokenPayload = verifyToken(refreshToken);
if (tokenPayload === TokenError.EXPIRED) {
error(401, "Refresh token expired");
} else if (tokenPayload === TokenError.INVALID || tokenPayload.type !== "refresh") {
error(401, "Invalid refresh token");
}
return tokenData;
const tokenData = await getRefreshToken(tokenPayload.jti);
if (!tokenData) {
error(500, "Refresh token not found");
}
return {
jti: tokenPayload.jti,
userId: tokenData.userId,
clientId: tokenData.clientId ?? undefined,
};
};
export const logout = async (refreshToken: string) => {
await verifyRefreshToken(refreshToken);
await revokeToken(refreshToken);
const { jti } = await verifyRefreshToken(refreshToken);
await revokeRefreshToken(jti);
};
export const refreshToken = async (refreshToken: string) => {
const tokenData = await verifyRefreshToken(refreshToken);
const { jti: oldJti, userId, clientId } = await verifyRefreshToken(refreshToken);
const newJti = uuidv4();
await revokeToken(refreshToken);
if (!(await rotateRefreshToken(oldJti, newJti))) {
error(500, "Refresh token not found");
}
return {
accessToken: issueToken("access", tokenData.userId, tokenData.clientId),
refreshToken: issueToken("refresh", tokenData.userId, tokenData.clientId),
accessToken: issueAccessToken(userId, clientId),
refreshToken: issueToken({ type: "refresh", jti: newJti }),
};
};