refactor(api): ♻️ Rewrite full authentication code to go OpenID-only

This commit is contained in:
Jesse Wierzbinski 2025-08-21 00:45:58 +02:00
parent 4eae4cd062
commit 1bfc5fb013
No known key found for this signature in database
39 changed files with 3076 additions and 2009 deletions

View file

@ -0,0 +1,46 @@
CREATE TABLE "AuthorizationCodes" (
"code" text PRIMARY KEY NOT NULL,
"scopes" text[] DEFAULT ARRAY[]::text[] NOT NULL,
"redirect_uri" text,
"expires_at" timestamp(3) NOT NULL,
"created_at" timestamp(3) DEFAULT now() NOT NULL,
"code_challenge" text,
"code_challenge_method" text,
"userId" uuid NOT NULL,
"clientId" text NOT NULL
);
--> statement-breakpoint
ALTER TABLE "Tokens" RENAME COLUMN "applicationId" TO "clientId";--> statement-breakpoint
--ALTER TABLE "Notes" DROP CONSTRAINT "Notes_applicationId_Applications_id_fk";
--> statement-breakpoint
--ALTER TABLE "OpenIdLoginFlows" DROP CONSTRAINT "OpenIdLoginFlows_applicationId_Applications_id_fk";
--> statement-breakpoint
--ALTER TABLE "Tokens" DROP CONSTRAINT "Tokens_applicationId_Applications_id_fk";
--> statement-breakpoint
DROP INDEX "Applications_client_id_index";--> statement-breakpoint
ALTER TABLE "Applications" ADD PRIMARY KEY ("client_id");--> statement-breakpoint
ALTER TABLE "Applications" ALTER COLUMN "scopes" SET DATA TYPE text[] USING (string_to_array("scopes", ' ')::text[]);--> statement-breakpoint
ALTER TABLE "Applications" ALTER COLUMN "scopes" SET DEFAULT ARRAY[]::text[];--> statement-breakpoint
ALTER TABLE "Notes" ALTER COLUMN "applicationId" SET DATA TYPE text;--> statement-breakpoint
ALTER TABLE "OpenIdLoginFlows" ALTER COLUMN "applicationId" SET DATA TYPE text;--> statement-breakpoint
ALTER TABLE "Applications" ADD COLUMN "redirect_uris" text[] DEFAULT ARRAY[]::text[] NOT NULL;--> statement-breakpoint
ALTER TABLE "OpenIdLoginFlows" ADD COLUMN "state" text;--> statement-breakpoint
ALTER TABLE "OpenIdLoginFlows" ADD COLUMN "client_state" text;--> statement-breakpoint
ALTER TABLE "OpenIdLoginFlows" ADD COLUMN "client_redirect_uri" text;--> statement-breakpoint
ALTER TABLE "OpenIdLoginFlows" ADD COLUMN "client_scopes" text[];--> statement-breakpoint
ALTER TABLE "Tokens" ADD COLUMN "scopes" text[] DEFAULT ARRAY[]::text[] NOT NULL;--> statement-breakpoint
ALTER TABLE "AuthorizationCodes" ADD CONSTRAINT "AuthorizationCodes_userId_Users_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."Users"("id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
ALTER TABLE "AuthorizationCodes" ADD CONSTRAINT "AuthorizationCodes_clientId_Applications_client_id_fk" FOREIGN KEY ("clientId") REFERENCES "public"."Applications"("client_id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
ALTER TABLE "Notes" ADD CONSTRAINT "Notes_applicationId_Applications_client_id_fk" FOREIGN KEY ("applicationId") REFERENCES "public"."Applications"("client_id") ON DELETE set null ON UPDATE cascade;--> statement-breakpoint
ALTER TABLE "OpenIdLoginFlows" ADD CONSTRAINT "OpenIdLoginFlows_applicationId_Applications_client_id_fk" FOREIGN KEY ("applicationId") REFERENCES "public"."Applications"("client_id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
ALTER TABLE "Tokens" ALTER COLUMN "clientId" SET DATA TYPE text;--> statement-breakpoint
ALTER TABLE "Tokens" ADD CONSTRAINT "Tokens_clientId_Applications_client_id_fk" FOREIGN KEY ("clientId") REFERENCES "public"."Applications"("client_id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
ALTER TABLE "Applications" DROP COLUMN "id";--> statement-breakpoint
ALTER TABLE "Applications" DROP COLUMN "vapid_key";--> statement-breakpoint
ALTER TABLE "Applications" DROP COLUMN "redirect_uri";--> statement-breakpoint
ALTER TABLE "Tokens" DROP COLUMN "token_type";--> statement-breakpoint
ALTER TABLE "Tokens" DROP COLUMN "scope";--> statement-breakpoint
ALTER TABLE "Tokens" DROP COLUMN "code";--> statement-breakpoint
ALTER TABLE "Tokens" DROP COLUMN "client_id";--> statement-breakpoint
ALTER TABLE "Tokens" DROP COLUMN "redirect_uri";--> statement-breakpoint
ALTER TABLE "Tokens" DROP COLUMN "id_token";

File diff suppressed because it is too large Load diff

View file

@ -358,6 +358,13 @@
"when": 1746368175263,
"tag": "0050_thick_lester",
"breakpoints": true
},
{
"idx": 51,
"version": "7",
"when": 1755729662013,
"tag": "0051_stiff_morbius",
"breakpoints": true
}
]
}

View file

@ -28,6 +28,7 @@ import {
import type { z } from "zod/v4";
const createdAt = () =>
// TODO: Change mode to Date
timestamp("created_at", { precision: 3, mode: "string" })
.defaultNow()
.notNull();
@ -39,7 +40,7 @@ const updatedAt = () =>
const uri = () => text("uri").unique();
const id = () => uuid("id").primaryKey().notNull();
const id = () => uuid("id").primaryKey();
export const Challenges = pgTable("Challenges", {
id: id(),
@ -308,47 +309,41 @@ export const RelationshipsRelations = relations(Relationships, ({ one }) => ({
}),
}));
export const Applications = pgTable(
"Applications",
{
id: id(),
name: text("name").notNull(),
website: text("website"),
vapidKey: text("vapid_key"),
clientId: text("client_id").notNull(),
secret: text("secret").notNull(),
scopes: text("scopes").notNull(),
redirectUri: text("redirect_uri").notNull(),
},
(table) => [uniqueIndex().on(table.clientId)],
);
export const Clients = pgTable("Applications", {
id: text("client_id").primaryKey(),
secret: text("secret").notNull(),
redirectUris: text("redirect_uris")
.array()
.notNull()
.default(sql`ARRAY[]::text[]`),
scopes: text("scopes").array().notNull().default(sql`ARRAY[]::text[]`),
name: text("name").notNull(),
website: text("website"),
});
export const ApplicationsRelations = relations(Applications, ({ many }) => ({
export const ClientsRelations = relations(Clients, ({ many }) => ({
tokens: many(Tokens),
loginFlows: many(OpenIdLoginFlows),
}));
export const Tokens = pgTable("Tokens", {
id: id(),
tokenType: text("token_type").notNull(),
scope: text("scope").notNull(),
scopes: text("scopes").array().notNull().default(sql`ARRAY[]::text[]`),
accessToken: text("access_token").notNull(),
code: text("code"),
expiresAt: timestamp("expires_at", { precision: 3, mode: "string" }),
createdAt: createdAt(),
clientId: text("client_id").notNull().default(""),
redirectUri: text("redirect_uri").notNull().default(""),
idToken: text("id_token"),
userId: uuid("userId")
.references(() => Users.id, {
onDelete: "cascade",
onUpdate: "cascade",
})
.notNull(),
applicationId: uuid("applicationId").references(() => Applications.id, {
onDelete: "cascade",
onUpdate: "cascade",
}),
clientId: text("clientId")
.references(() => Clients.id, {
onDelete: "cascade",
onUpdate: "cascade",
})
.notNull(),
});
export const TokensRelations = relations(Tokens, ({ one }) => ({
@ -356,12 +351,51 @@ export const TokensRelations = relations(Tokens, ({ one }) => ({
fields: [Tokens.userId],
references: [Users.id],
}),
application: one(Applications, {
fields: [Tokens.applicationId],
references: [Applications.id],
client: one(Clients, {
fields: [Tokens.clientId],
references: [Clients.id],
}),
}));
export const AuthorizationCodes = pgTable("AuthorizationCodes", {
code: text("code").primaryKey(),
scopes: text("scopes").array().notNull().default(sql`ARRAY[]::text[]`),
redirectUri: text("redirect_uri"),
expiresAt: timestamp("expires_at", {
precision: 3,
mode: "string",
}).notNull(),
createdAt: createdAt(),
codeChallenge: text("code_challenge"),
codeChallengeMethod: text("code_challenge_method"),
userId: uuid("userId")
.references(() => Users.id, {
onDelete: "cascade",
onUpdate: "cascade",
})
.notNull(),
clientId: text("clientId")
.references(() => Clients.id, {
onDelete: "cascade",
onUpdate: "cascade",
})
.notNull(),
});
export const AuthorizationCodesRelations = relations(
AuthorizationCodes,
({ one }) => ({
user: one(Users, {
fields: [AuthorizationCodes.userId],
references: [Users.id],
}),
client: one(Clients, {
fields: [AuthorizationCodes.clientId],
references: [Clients.id],
}),
}),
);
export const Medias = pgTable("Medias", {
id: id(),
content: jsonb("content")
@ -460,7 +494,7 @@ export const Notes = pgTable("Notes", {
}),
sensitive: boolean("sensitive").notNull().default(false),
spoilerText: text("spoiler_text").default("").notNull(),
applicationId: uuid("applicationId").references(() => Applications.id, {
applicationId: text("applicationId").references(() => Clients.id, {
onDelete: "set null",
onUpdate: "cascade",
}),
@ -494,9 +528,9 @@ export const NotesRelations = relations(Notes, ({ many, one }) => ({
references: [Notes.id],
relationName: "NoteToQuotes",
}),
application: one(Applications, {
application: one(Clients, {
fields: [Notes.applicationId],
references: [Applications.id],
references: [Clients.id],
}),
quotes: many(Notes, {
relationName: "NoteToQuotes",
@ -665,7 +699,11 @@ export const UsersRelations = relations(Users, ({ many, one }) => ({
export const OpenIdLoginFlows = pgTable("OpenIdLoginFlows", {
id: id(),
codeVerifier: text("code_verifier").notNull(),
applicationId: uuid("applicationId").references(() => Applications.id, {
state: text("state"),
clientState: text("client_state"),
clientRedirectUri: text("client_redirect_uri"),
clientScopes: text("client_scopes").array(),
applicationId: text("applicationId").references(() => Clients.id, {
onDelete: "cascade",
onUpdate: "cascade",
}),
@ -675,9 +713,9 @@ export const OpenIdLoginFlows = pgTable("OpenIdLoginFlows", {
export const OpenIdLoginFlowsRelations = relations(
OpenIdLoginFlows,
({ one }) => ({
application: one(Applications, {
application: one(Clients, {
fields: [OpenIdLoginFlows.applicationId],
references: [Applications.id],
references: [Clients.id],
}),
}),
);