mirror of
https://github.com/bretzel-app/crumbs.git
synced 2026-10-13 04:06:57 +02:00
feat(auth): OAuth authorize and callback endpoints
Dynamic [provider] routes for Google, GitHub, and OIDC. Stores state and PKCE verifier in httpOnly cookies. Callback validates code, finds/links user by provider ID or email (invite-only), and creates session. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
committed by
Fred Cabassut
co-authored by
Claude Opus 4.6
parent
8806ffd50a
commit
a9c771cc9f
@@ -266,6 +266,36 @@ export function updateUserRole(userId: number, role: 'admin' | 'user'): void {
|
||||
db.update(users).set({ role }).where(eq(users.id, userId)).run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a user by OAuth provider, or by email. Invite-only: rejects if no matching user.
|
||||
*/
|
||||
export function findOrLinkOAuthUser(
|
||||
provider: string,
|
||||
providerId: string,
|
||||
email: string,
|
||||
name: string
|
||||
): User | null {
|
||||
// First try exact provider+providerId match
|
||||
const byProvider = db
|
||||
.select()
|
||||
.from(users)
|
||||
.where(and(eq(users.authProvider, provider), eq(users.providerId, providerId)))
|
||||
.get();
|
||||
if (byProvider) return toUser(byProvider);
|
||||
|
||||
// Try matching by email (invite-only: user must already exist)
|
||||
const byEmail = db.select().from(users).where(eq(users.email, email)).get();
|
||||
if (!byEmail) return null; // No matching user — not invited
|
||||
|
||||
// Link this OAuth provider to the existing user
|
||||
db.update(users)
|
||||
.set({ authProvider: provider, providerId, displayName: byEmail.displayName || name })
|
||||
.where(eq(users.id, byEmail.id))
|
||||
.run();
|
||||
|
||||
return toUser({ ...byEmail, authProvider: provider, providerId });
|
||||
}
|
||||
|
||||
export function updateUserProfile(
|
||||
userId: number,
|
||||
data: { displayName?: string; email?: string }
|
||||
|
||||
Reference in New Issue
Block a user