Files
football-next/app/api/auth/mobile/refresh/route.ts
2026-05-11 16:06:47 +03:30

72 lines
2.1 KiB
TypeScript

import { NextRequest, NextResponse } from "next/server";
import { db } from "@/lib/db";
import {
ACCESS_TOKEN_EXPIRES_IN,
REFRESH_TOKEN_EXPIRES_IN,
createMobileTokenPair,
hashToken,
revokeRefreshTokenFamily,
} from "@/lib/mobileTokens";
export async function POST(req: NextRequest) {
const { refreshToken } = await req.json().catch(() => ({}));
if (typeof refreshToken !== "string" || !refreshToken.trim()) {
return NextResponse.json({ error: "refreshToken is required" }, { status: 400 });
}
const existingRefreshToken = await db.refreshToken.findUnique({
where: { tokenHash: hashToken(refreshToken.trim()) },
include: {
user: {
select: {
id: true,
name: true,
phone: true,
role: true,
},
},
},
});
if (!existingRefreshToken) {
return NextResponse.json({ error: "Invalid refresh token" }, { status: 401 });
}
if (existingRefreshToken.revokedAt) {
await revokeRefreshTokenFamily(existingRefreshToken.userId, existingRefreshToken.familyId);
return NextResponse.json({ error: "Refresh token has been revoked" }, { status: 401 });
}
if (existingRefreshToken.expiresAt <= new Date()) {
await db.refreshToken.update({
where: { id: existingRefreshToken.id },
data: { revokedAt: new Date() },
});
return NextResponse.json({ error: "Refresh token has expired" }, { status: 401 });
}
const tokens = await createMobileTokenPair(existingRefreshToken.userId, existingRefreshToken.familyId);
await db.refreshToken.update({
where: { id: existingRefreshToken.id },
data: {
revokedAt: new Date(),
replacedByTokenId: tokens.refreshTokenId,
},
});
return NextResponse.json({
accessToken: tokens.accessToken,
token: tokens.accessToken,
tokenType: "Bearer",
expiresIn: ACCESS_TOKEN_EXPIRES_IN,
expiresAt: tokens.accessTokenExpiresAt.toISOString(),
refreshToken: tokens.refreshToken,
refreshExpiresIn: REFRESH_TOKEN_EXPIRES_IN,
refreshExpiresAt: tokens.refreshTokenExpiresAt.toISOString(),
user: existingRefreshToken.user,
});
}