hugging-c-ai / src /lib /auth.js
NeoPy's picture
feat: Hugging-c-ai v2 — HF OAuth + multi-provider AI + HF bucket storage + Gradio
60faa09
Raw
History Blame Contribute Delete
4.69 kB
import { PrismaAdapter } from "@next-auth/prisma-adapter";
import CredentialsProvider from "next-auth/providers/credentials";
import { prisma } from "./prisma";
import HuggingFaceProvider from "./providers/huggingface";
export const authOptions = {
adapter: PrismaAdapter(prisma),
session: { strategy: "jwt" },
providers: [
HuggingFaceProvider({
clientId: process.env.HF_CLIENT_ID,
clientSecret: process.env.HF_CLIENT_SECRET,
}),
CredentialsProvider({
id: "credentials",
name: "API Key / HF Token",
credentials: {
apiKey: { label: "API Key or HF Token", type: "password" },
},
async authorize(credentials) {
if (!credentials?.apiKey) throw new Error("API Key is required");
const apiKey = credentials.apiKey.trim();
if (apiKey.length < 5) throw new Error("Invalid API key format");
let hfUser = null;
if (apiKey.startsWith("hf_")) {
try {
const r = await fetch("https://huggingface.co/api/whoami-v2", {
headers: { Authorization: `Bearer ${apiKey}` },
});
if (r.ok) {
const j = await r.json();
hfUser = {
name: j.name || j.fullname || "HF User",
username: j.name,
email: j.email || `${j.name}@users.huggingface.co`,
};
}
} catch (e) {
console.warn("[HF_WHOAMI_FAILED]", e.message);
}
}
const dummyEmail = hfUser?.email || `apikey_${apiKey.slice(-8)}@local.invalid`;
let dbUser = await prisma.user.findFirst({
where: { OR: [{ customApiKey: apiKey }, { email: dummyEmail }] },
});
if (!dbUser) {
dbUser = await prisma.user.create({
data: {
name: hfUser?.name || "API Key User",
email: dummyEmail,
customApiKey: apiKey,
hfUsername: hfUser?.username || null,
credits: 0,
},
});
} else if (!dbUser.customApiKey) {
dbUser = await prisma.user.update({
where: { id: dbUser.id },
data: { customApiKey: apiKey },
});
}
return {
id: dbUser.id,
name: dbUser.name,
email: dbUser.email,
image: dbUser.image || null,
credits: dbUser.credits,
customApiKey: dbUser.customApiKey || apiKey,
isApiKeyUser: true,
};
},
}),
],
callbacks: {
async jwt({ token, user, account, trigger, session }) {
if (account?.access_token) {
token.hfAccessToken = account.access_token;
token.hfRefreshToken = account.refresh_token;
}
if (user) {
token.id = user.id;
token.credits = user.credits;
token.customApiKey = user.customApiKey;
token.isApiKeyUser = user.isApiKeyUser || false;
if (user.hfUsername) token.hfUsername = user.hfUsername;
}
if (trigger === "update" && session) {
if (session.customApiKey !== undefined) token.customApiKey = session.customApiKey;
if (session.credits !== undefined) token.credits = session.credits;
}
const userId = token.id || token.sub;
if (userId) {
token.id = userId;
try {
const dbUser = await prisma.user.findUnique({
where: { id: userId },
select: {
credits: true,
customApiKey: true,
hfUsername: true,
accounts: {
where: { provider: "huggingface" },
select: { access_token: true },
take: 1,
},
},
});
if (dbUser) {
token.credits = dbUser.credits;
token.customApiKey = dbUser.customApiKey;
if (dbUser.hfUsername) token.hfUsername = dbUser.hfUsername;
if (dbUser.accounts?.[0]?.access_token) {
token.hfAccessToken = dbUser.accounts[0].access_token;
}
}
} catch (err) {}
}
return token;
},
async session({ session, token }) {
if (session.user && token) {
session.user.id = token.id || token.sub;
session.user.credits = token.credits;
session.user.customApiKey = token.customApiKey;
session.user.isApiKeyUser = Boolean(token.customApiKey);
session.user.hfUsername = token.hfUsername || null;
session.user.hfAccessToken = token.hfAccessToken || null;
}
return session;
},
},
secret: process.env.NEXTAUTH_SECRET,
pages: { signIn: "/login" },
};