fix(api): 🐛 Fix OAuth login bugs

This commit is contained in:
Jesse Wierzbinski 2024-05-01 18:34:24 -10:00
parent edf62aa015
commit 0baa9dd12d
No known key found for this signature in database
3 changed files with 52 additions and 16 deletions

View file

@ -37,7 +37,7 @@ export default apiRoute<typeof meta, typeof schema>(
.insert(Applications) .insert(Applications)
.values({ .values({
name: client_name || "", name: client_name || "",
redirectUri: redirect_uris || "", redirectUri: decodeURIComponent(redirect_uris) || "",
scopes: scopes || "read", scopes: scopes || "read",
website: website || null, website: website || null,
clientId: randomBytes(32).toString("base64url"), clientId: randomBytes(32).toString("base64url"),

View file

@ -52,16 +52,22 @@ export const querySchema = z.object({
.default(60 * 60 * 24 * 7), .default(60 * 60 * 24 * 7),
}); });
const returnError = (error: string, description: string) => const returnError = (query: object, error: string, description: string) => {
response(null, 302, { const searchParams = new URLSearchParams();
Location: new URL(
`/oauth/authorize?${new URLSearchParams({ // Add all data that is not undefined except email and password
error: error, for (const [key, value] of Object.entries(query)) {
error_description: description, if (key !== "email" && key !== "password" && value !== undefined)
}).toString()}`, searchParams.append(key, value);
config.http.base_url, }
).toString(),
searchParams.append("error", error);
searchParams.append("error_description", description);
return response(null, 302, {
Location: `/oauth/authorize?${searchParams.toString()}`,
}); });
};
/** /**
* OIDC Authorization * OIDC Authorization
@ -82,6 +88,7 @@ export default apiRoute<typeof meta, typeof schema>(
if (!cookie) if (!cookie)
return returnError( return returnError(
extraData.parsedRequest,
"invalid_request", "invalid_request",
"No cookies were sent with the request", "No cookies were sent with the request",
); );
@ -93,6 +100,7 @@ export default apiRoute<typeof meta, typeof schema>(
if (!jwt) if (!jwt)
return returnError( return returnError(
extraData.parsedRequest,
"invalid_request", "invalid_request",
"No jwt cookie was sent in the request", "No jwt cookie was sent in the request",
); );
@ -125,20 +133,41 @@ export default apiRoute<typeof meta, typeof schema>(
if (!result) if (!result)
return returnError( return returnError(
extraData.parsedRequest,
"invalid_request", "invalid_request",
"Invalid JWT, could not verify", "Invalid JWT, could not verify",
); );
const payload = result.payload; const payload = result.payload;
if (!payload.sub) return returnError("invalid_request", "Invalid sub"); if (!payload.sub)
if (!payload.aud) return returnError("invalid_request", "Invalid aud"); return returnError(
if (!payload.exp) return returnError("invalid_request", "Invalid exp"); extraData.parsedRequest,
"invalid_request",
"Invalid sub",
);
if (!payload.aud)
return returnError(
extraData.parsedRequest,
"invalid_request",
"Invalid aud",
);
if (!payload.exp)
return returnError(
extraData.parsedRequest,
"invalid_request",
"Invalid exp",
);
// Check if the user is authenticated // Check if the user is authenticated
const user = await User.fromId(payload.sub); const user = await User.fromId(payload.sub);
if (!user) return returnError("invalid_request", "Invalid sub"); if (!user)
return returnError(
extraData.parsedRequest,
"invalid_request",
"Invalid sub",
);
const responseTypes = response_type.split(" "); const responseTypes = response_type.split(" ");
@ -148,12 +177,14 @@ export default apiRoute<typeof meta, typeof schema>(
if (!asksCode && !asksToken && !asksIdToken) if (!asksCode && !asksToken && !asksIdToken)
return returnError( return returnError(
extraData.parsedRequest,
"invalid_request", "invalid_request",
"Invalid response_type, must ask for code, token, or id_token", "Invalid response_type, must ask for code, token, or id_token",
); );
if (asksCode && !redirect_uri) if (asksCode && !redirect_uri)
return returnError( return returnError(
extraData.parsedRequest,
"invalid_request", "invalid_request",
"Redirect URI is required for code flow", "Redirect URI is required for code flow",
); );
@ -177,12 +208,14 @@ export default apiRoute<typeof meta, typeof schema>(
if (!application) if (!application)
return returnError( return returnError(
extraData.parsedRequest,
"invalid_client", "invalid_client",
"Invalid client_id or client_secret", "Invalid client_id or client_secret",
); );
if (application.redirectUri !== redirect_uri) if (application.redirectUri !== redirect_uri)
return returnError( return returnError(
extraData.parsedRequest,
"invalid_request", "invalid_request",
"Redirect URI does not match client_id", "Redirect URI does not match client_id",
); );
@ -197,7 +230,11 @@ export default apiRoute<typeof meta, typeof schema>(
scope && scope &&
!scope.split(" ").every((s) => applicationScopes.includes(s)) !scope.split(" ").every((s) => applicationScopes.includes(s))
) )
return returnError("invalid_scope", "Invalid scope"); return returnError(
extraData.parsedRequest,
"invalid_scope",
"Invalid scope",
);
// Generate tokens // Generate tokens
const code = randomBytes(256).toString("base64url"); const code = randomBytes(256).toString("base64url");

View file

@ -4,7 +4,6 @@ import { eq } from "drizzle-orm";
import { z } from "zod"; import { z } from "zod";
import { db } from "~drizzle/db"; import { db } from "~drizzle/db";
import { Tokens } from "~drizzle/schema"; import { Tokens } from "~drizzle/schema";
import { config } from "~packages/config-manager";
export const meta = applyConfig({ export const meta = applyConfig({
allowedMethods: ["POST"], allowedMethods: ["POST"],