/home/techb158/balavpn.abdallabala.com/src/services
Edit: /home/techb158/balavpn.abdallabala.com/src/services/sso-service.js (3167B)
const { prisma } = require("../lib/prisma");
const { createSession } = require("./auth-service");
const { getOidcConfig, discoverProvider, generateNonce, decodeJwtPayload } = require("../lib/oidc");
async function exchangeCode(code, redirectUrl, clientId, clientSecret, tokenEndpoint) {
const body = new URLSearchParams({
grant_type: "authorization_code",
code,
redirect_uri: redirectUrl,
client_id: clientId,
client_secret: clientSecret,
});
const res = await fetch(tokenEndpoint, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: body.toString(),
});
if (!res.ok) {
const text = await res.text();
throw new Error(`Token exchange failed (${res.status}): ${text}`);
}
return res.json();
}
async function handleSsoCallback(code) {
const config = getOidcConfig();
if (!config) throw Object.assign(new Error("SSO not configured"), { status: 501 });
const disco = await discoverProvider(config.issuer);
const tokens = await exchangeCode(code, config.redirectUrl, config.clientId, config.clientSecret, disco.token_endpoint);
const idToken = tokens.id_token;
if (!idToken) throw Object.assign(new Error("No id_token returned from provider"), { status: 400 });
const claims = decodeJwtPayload(idToken);
const email = claims.email;
if (!email) throw Object.assign(new Error("Email not provided by SSO provider"), { status: 400 });
const displayName = claims.name || claims.preferred_username || email.split("@")[0];
let user = await prisma.user.findUnique({ where: { email } });
if (!user) {
user = await prisma.user.create({
data: { email, displayName, emailVerifiedAt: new Date() },
});
const slug = displayName.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "")
+ "-" + Date.now().toString(36);
const role = await prisma.role.upsert({
where: { code: "owner" },
update: {},
create: { code: "owner", name: "Owner", permissions: ["*"], system: true },
});
const org = await prisma.organization.create({
data: { name: `${displayName}'s Organization`, slug, status: "TRIAL", planCode: "pilot", manualBilling: true },
});
await prisma.membership.create({
data: { organizationId: org.id, userId: user.id, roleId: role.id, status: "ACTIVE" },
});
await prisma.subscription.create({
data: { organizationId: org.id, source: "MANUAL", status: "TRIALING", planCode: "pilot", userLimit: 5, projectLimit: 3 },
}).catch(() => {});
const workspace = await prisma.workspace.create({
data: { organizationId: org.id, name: "Default Workspace", slug: "default-workspace", type: "B2B_TEAM", status: "TRIAL" },
});
await prisma.project.create({
data: { workspaceId: workspace.id, name: "My Project", projectType: "AI-Enabler", status: "Active", riskAppetite: 50 },
});
} else {
await prisma.user.update({
where: { id: user.id },
data: { lastLoginAt: new Date(), displayName },
});
}
const session = await createSession(user.id);
return { user, session };
}
module.exports = { handleSsoCallback };