feat(auth): link credentials users with OIDC

This commit is contained in:
ajnart committed 2026-07-22 22:51:49 +02:00
1 parent cf0e469465
commit 00a65bfc58
8 files changed
+159 -15

No files matched your search

+21 -4
View File
@@ -6,20 +6,24 @@ import { and, eq } from "@homarr/db";
import { accounts, sessions, users } from "@homarr/db/schema";
import type { SupportedAuthProvider } from "@homarr/definitions";
export const createAdapter = (db: Database, provider: SupportedAuthProvider | "unknown"): Adapter => {
export const createAdapter = (
db: Database,
provider: SupportedAuthProvider | "unknown",
enableDangerousCredentialsLinking = false,
): Adapter => {
const drizzleAdapter = DrizzleAdapter(db, { usersTable: users, sessionsTable: sessions, accountsTable: accounts });
return {
...drizzleAdapter,
// We override the default implementation as we want to have a provider
// flag in the user instead of the account to not intermingle users from different providers
// Keep users isolated by their primary provider. The explicit credentials-linking
// opt-in is the only exception and keeps credentials as the primary provider.
// eslint-disable-next-line no-restricted-syntax
getUserByEmail: async (email) => {
if (provider === "unknown") {
throw new Error("Unable to get user by email for unknown provider");
}
const user = await db.query.users.findFirst({
let user = await db.query.users.findFirst({
where: and(eq(users.email, email), eq(users.provider, provider)),
columns: {
id: true,
@@ -30,6 +34,19 @@ export const createAdapter = (db: Database, provider: SupportedAuthProvider | "u
},
});
if (!user && provider === "oidc" && enableDangerousCredentialsLinking) {
user = await db.query.users.findFirst({
where: and(eq(users.email, email), eq(users.provider, "credentials")),
columns: {
id: true,
name: true,
email: true,
emailVerified: true,
image: true,
},
});
}
if (!user) {
return null;
}