first commit
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
import { test, expect } from "bun:test";
|
||||
import {
|
||||
google,
|
||||
github,
|
||||
discord,
|
||||
defineProvider,
|
||||
startAuth,
|
||||
exchangeCode,
|
||||
completeAuth,
|
||||
randomToken,
|
||||
} from "../src/index.ts";
|
||||
|
||||
const CREDS = { clientId: "cid", clientSecret: "secret" };
|
||||
|
||||
test("presets have the right endpoints + scopes", () => {
|
||||
expect(google(CREDS).authorizeUrl).toContain("accounts.google.com");
|
||||
expect(github(CREDS).scopes).toContain("user:email");
|
||||
expect(discord(CREDS).userInfoUrl).toContain("discord.com/api/users/@me");
|
||||
});
|
||||
|
||||
test("startAuth builds an authorize URL with PKCE + state", async () => {
|
||||
const { url, state, verifier } = await startAuth(google(CREDS), {
|
||||
redirectUri: "https://app.test/cb",
|
||||
});
|
||||
const u = new URL(url);
|
||||
expect(u.origin + u.pathname).toBe("https://accounts.google.com/o/oauth2/v2/auth");
|
||||
expect(u.searchParams.get("client_id")).toBe("cid");
|
||||
expect(u.searchParams.get("redirect_uri")).toBe("https://app.test/cb");
|
||||
expect(u.searchParams.get("response_type")).toBe("code");
|
||||
expect(u.searchParams.get("scope")).toBe("openid email profile");
|
||||
expect(u.searchParams.get("state")).toBe(state);
|
||||
expect(u.searchParams.get("code_challenge")).toBeTruthy();
|
||||
expect(u.searchParams.get("code_challenge_method")).toBe("S256");
|
||||
expect(u.searchParams.get("access_type")).toBe("offline"); // provider default param
|
||||
expect(verifier.length).toBeGreaterThan(20);
|
||||
});
|
||||
|
||||
test("randomToken is URL-safe and unique", () => {
|
||||
const a = randomToken();
|
||||
const b = randomToken();
|
||||
expect(a).not.toBe(b);
|
||||
expect(a).toMatch(/^[A-Za-z0-9_-]+$/);
|
||||
});
|
||||
|
||||
test("exchangeCode posts the code + PKCE verifier and parses tokens", async () => {
|
||||
let captured: { url: string; body: string } | null = null;
|
||||
const fakeFetch = (async (url: string, init: RequestInit) => {
|
||||
captured = { url: String(url), body: String(init.body) };
|
||||
return new Response(JSON.stringify({ access_token: "tok", token_type: "Bearer" }), {
|
||||
headers: { "content-type": "application/json" },
|
||||
});
|
||||
}) as unknown as typeof fetch;
|
||||
|
||||
const tokens = await exchangeCode(github(CREDS), {
|
||||
code: "abc",
|
||||
redirectUri: "https://app.test/cb",
|
||||
verifier: "ver123",
|
||||
fetch: fakeFetch,
|
||||
});
|
||||
expect(tokens.access_token).toBe("tok");
|
||||
expect(captured!.url).toBe("https://github.com/login/oauth/access_token");
|
||||
expect(captured!.body).toContain("code=abc");
|
||||
expect(captured!.body).toContain("code_verifier=ver123");
|
||||
expect(captured!.body).toContain("grant_type=authorization_code");
|
||||
});
|
||||
|
||||
test("completeAuth maps the provider profile (custom provider)", async () => {
|
||||
const provider = defineProvider({
|
||||
name: "acme",
|
||||
authorizeUrl: "https://acme.test/authorize",
|
||||
tokenUrl: "https://acme.test/token",
|
||||
userInfoUrl: "https://acme.test/me",
|
||||
scopes: ["email"],
|
||||
clientId: "cid",
|
||||
clientSecret: "secret",
|
||||
mapProfile: (raw) => ({ id: String(raw.user_id), email: raw.mail as string, name: "n", raw }),
|
||||
});
|
||||
const fakeFetch = (async (url: string) => {
|
||||
if (String(url).endsWith("/token"))
|
||||
return new Response(JSON.stringify({ access_token: "t" }), {
|
||||
headers: { "content-type": "application/json" },
|
||||
});
|
||||
return new Response(JSON.stringify({ user_id: 99, mail: "x@acme.test" }), {
|
||||
headers: { "content-type": "application/json" },
|
||||
});
|
||||
}) as unknown as typeof fetch;
|
||||
|
||||
const { profile } = await completeAuth(provider, {
|
||||
code: "c",
|
||||
redirectUri: "r",
|
||||
fetch: fakeFetch,
|
||||
});
|
||||
expect(profile.id).toBe("99");
|
||||
expect(profile.email).toBe("x@acme.test");
|
||||
});
|
||||
Reference in New Issue
Block a user