server/packages/api/routes/oauth/token.test.ts

191 lines
6.5 KiB
TypeScript
Raw Permalink Normal View History

import { afterAll, describe, expect, test } from "bun:test";
import { Client, db } from "@versia-server/kit/db";
import { fakeRequest, getTestUsers } from "@versia-server/tests";
import { randomUUIDv7 } from "bun";
import { eq } from "drizzle-orm";
import { randomString } from "@/math";
import { AuthorizationCodes } from "~/packages/kit/tables/schema";
const { deleteUsers, users } = await getTestUsers(1);
const application = await Client.insert({
id: randomUUIDv7(),
redirectUris: ["https://example.com/callback"],
scopes: ["openid", "profile", "email"],
secret: "test-secret",
name: "Test Application",
});
const authorizationCode = (
await db
.insert(AuthorizationCodes)
.values({
clientId: application.id,
code: randomString(10),
redirectUri: application.data.redirectUris[0],
userId: users[0].id,
expiresAt: new Date(Date.now() + 300 * 1000).toISOString(),
})
.returning()
)[0];
afterAll(async () => {
await deleteUsers();
await application.delete();
await db
.delete(AuthorizationCodes)
.where(eq(AuthorizationCodes.code, authorizationCode.code));
});
describe("/oauth/token", () => {
test("should return token with valid inputs", async () => {
const response = await fakeRequest("/oauth/token", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
grant_type: "authorization_code",
code: authorizationCode.code,
redirect_uri: application.data.redirectUris[0],
client_id: application.data.id,
client_secret: application.data.secret,
}),
});
expect(response.status).toBe(200);
const body = await response.json();
expect(body.access_token).toBeString();
expect(body.token_type).toBe("Bearer");
expect(body.expires_in).toBeNull();
});
test("should return error for missing code", async () => {
const response = await fakeRequest("/oauth/token", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
grant_type: "authorization_code",
redirect_uri: application.data.redirectUris[0],
client_id: application.data.id,
client_secret: application.data.secret,
}),
});
expect(response.status).toBe(422);
const body = await response.json();
2025-11-21 08:31:02 +01:00
expect(body.error).toInclude(
`expected string, received undefined at "code"`,
);
});
test("should return error for missing redirect_uri", async () => {
const response = await fakeRequest("/oauth/token", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
grant_type: "authorization_code",
code: authorizationCode.code,
client_id: application.data.id,
client_secret: application.data.secret,
}),
});
expect(response.status).toBe(422);
const body = await response.json();
2025-11-21 08:31:02 +01:00
expect(body.error).toInclude(
`expected string, received undefined at "redirect_uri"`,
);
});
test("should return error for missing client_id", async () => {
const response = await fakeRequest("/oauth/token", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
grant_type: "authorization_code",
code: authorizationCode.code,
redirect_uri: application.data.redirectUris[0],
client_secret: application.data.secret,
}),
});
expect(response.status).toBe(422);
const body = await response.json();
2025-11-21 08:31:02 +01:00
expect(body.error).toInclude(
`expected string, received undefined at "client_id"`,
);
});
test("should return error for invalid client credentials", async () => {
const response = await fakeRequest("/oauth/token", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
grant_type: "authorization_code",
code: authorizationCode.code,
redirect_uri: application.data.redirectUris[0],
client_id: application.data.id,
client_secret: "invalid-secret",
}),
});
expect(response.status).toBe(401);
const body = await response.json();
expect(body.error).toBe("invalid_client");
expect(body.error_description).toBe("Invalid client credentials");
});
test("should return error for code not found", async () => {
const response = await fakeRequest("/oauth/token", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
grant_type: "authorization_code",
code: "invalid-code",
redirect_uri: application.data.redirectUris[0],
client_id: application.data.id,
client_secret: application.data.secret,
}),
});
expect(response.status).toBe(404);
const body = await response.json();
expect(body.error).toBe("invalid_grant");
expect(body.error_description).toBe(
"Authorization code not found or expired",
);
});
test("should return error for unsupported grant type", async () => {
const response = await fakeRequest("/oauth/token", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
grant_type: "refresh_token",
code: authorizationCode.code,
redirect_uri: application.data.redirectUris[0],
client_id: application.data.id,
client_secret: application.data.secret,
}),
});
expect(response.status).toBe(401);
const body = await response.json();
expect(body.error).toBe("unsupported_grant_type");
expect(body.error_description).toBe("Unsupported grant type");
});
});