mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-02 20:30:10 +00:00
fix(auth): send login token in POST body
This commit is contained in:
@@ -253,7 +253,8 @@ oidc.admin_claim_value = 'readmeabook-admin'
|
||||
|
||||
- Login token stored as SHA-256 hash in `User.loginTokenHash`
|
||||
- Admin generates/revokes via user permissions modal
|
||||
- User login with token `/auth/token/login?token=rmab_...`
|
||||
- User navigates to `/auth/token/login?token=rmab_...` → page POSTs token to API in request body
|
||||
- API: `POST /api/auth/token/login` with `{ token }` in JSON body
|
||||
- Invalid token redirects to `/login`
|
||||
|
||||
## Security
|
||||
|
||||
@@ -11,9 +11,9 @@ import crypto from 'crypto';
|
||||
|
||||
const logger = RMABLogger.create('API.Auth.TokenLogin');
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const token = request.nextUrl.searchParams.get('token');
|
||||
const { token } = await request.json();
|
||||
|
||||
if (!token) {
|
||||
return NextResponse.json({ error: 'Missing token parameter' }, { status: 400 });
|
||||
|
||||
@@ -22,7 +22,11 @@ function TokenLoginContent() {
|
||||
return;
|
||||
}
|
||||
|
||||
fetch(`/api/auth/token/login?token=${encodeURIComponent(token)}`)
|
||||
fetch('/api/auth/token/login', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ token }),
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((data) => {
|
||||
if (data.error) {
|
||||
@@ -35,7 +39,7 @@ function TokenLoginContent() {
|
||||
localStorage.setItem('user', JSON.stringify(data.user));
|
||||
|
||||
setAuthData(data.user, data.accessToken);
|
||||
window.location.href = '/';
|
||||
window.location.href = '/';
|
||||
})
|
||||
.catch(() => {
|
||||
router.replace('/login');
|
||||
|
||||
@@ -19,7 +19,7 @@ vi.mock('@/lib/utils/jwt', () => ({
|
||||
generateRefreshToken: generateRefreshTokenMock,
|
||||
}));
|
||||
|
||||
describe('GET /api/auth/token/login', () => {
|
||||
describe('POST /api/auth/token/login', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
generateAccessTokenMock.mockReturnValue('access-token');
|
||||
@@ -37,9 +37,9 @@ describe('GET /api/auth/token/login', () => {
|
||||
});
|
||||
prismaMock.user.update.mockResolvedValueOnce({});
|
||||
|
||||
const { GET } = await import('@/app/api/auth/token/login/route');
|
||||
const request = { nextUrl: { searchParams: new URLSearchParams('token=rmab_valid_token') } };
|
||||
const response = await GET(request as any);
|
||||
const { POST } = await import('@/app/api/auth/token/login/route');
|
||||
const request = { json: vi.fn().mockResolvedValue({ token: 'rmab_valid_token' }) };
|
||||
const response = await POST(request as any);
|
||||
const payload = await response.json();
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
@@ -50,9 +50,9 @@ describe('GET /api/auth/token/login', () => {
|
||||
});
|
||||
|
||||
it('returns 400 when token parameter is missing', async () => {
|
||||
const { GET } = await import('@/app/api/auth/token/login/route');
|
||||
const request = { nextUrl: { searchParams: new URLSearchParams() } };
|
||||
const response = await GET(request as any);
|
||||
const { POST } = await import('@/app/api/auth/token/login/route');
|
||||
const request = { json: vi.fn().mockResolvedValue({}) };
|
||||
const response = await POST(request as any);
|
||||
const payload = await response.json();
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
@@ -62,9 +62,9 @@ describe('GET /api/auth/token/login', () => {
|
||||
it('returns 401 when token is invalid or user not found', async () => {
|
||||
prismaMock.user.findFirst.mockResolvedValueOnce(null);
|
||||
|
||||
const { GET } = await import('@/app/api/auth/token/login/route');
|
||||
const request = { nextUrl: { searchParams: new URLSearchParams('token=rmab_invalid') } };
|
||||
const response = await GET(request as any);
|
||||
const { POST } = await import('@/app/api/auth/token/login/route');
|
||||
const request = { json: vi.fn().mockResolvedValue({ token: 'rmab_invalid' }) };
|
||||
const response = await POST(request as any);
|
||||
const payload = await response.json();
|
||||
|
||||
expect(response.status).toBe(401);
|
||||
|
||||
Reference in New Issue
Block a user