Phase6c: Optional Company contact name
All checks were successful
Build and Push / build (push) Successful in 1m42s
All checks were successful
Build and Push / build (push) Successful in 1m42s
This commit is contained in:
@@ -54,18 +54,23 @@ export const authConfig: NextAuthConfig = {
|
||||
// route through this branch. We trust the new value because the
|
||||
// PUT /api/settings/profile route already wrote it to ZITADEL
|
||||
// and re-fetched the canonical displayName before returning.
|
||||
// NextAuth maps token.name → session.user.name on the next
|
||||
// session callback, so downstream useSession() consumers see
|
||||
// the new name without a logout/login cycle.
|
||||
// The session callback reads token.name directly (see below) so
|
||||
// the update propagates without depending on auth.js's implicit
|
||||
// token→session.user mapping, which is flaky for the name claim
|
||||
// in the v5 OIDC provider configuration.
|
||||
//
|
||||
// Defensive: only the `name` field is accepted from the update
|
||||
// payload, even if the client passes additional keys. Other
|
||||
// identity claims (orgId, roles, sub) come from ZITADEL at
|
||||
// sign-in time and are not user-mutable from a settings page.
|
||||
//
|
||||
// Returns a NEW token object (spread) rather than mutating, so
|
||||
// there is no ambiguity for auth.js about whether the token
|
||||
// changed and needs re-encoding into the session cookie.
|
||||
if (trigger === "update" && session) {
|
||||
const update = session as { name?: unknown };
|
||||
if (typeof update.name === "string") {
|
||||
(token as { name?: string }).name = update.name;
|
||||
return { ...token, name: update.name };
|
||||
}
|
||||
return token;
|
||||
}
|
||||
@@ -77,6 +82,19 @@ export const authConfig: NextAuthConfig = {
|
||||
claims["urn:zitadel:iam:org:project:roles"]
|
||||
);
|
||||
token.accessToken = account.access_token;
|
||||
// Phase 6 fix5: explicitly pin the standard name/email claims
|
||||
// onto the token from the OIDC profile. Previously these came
|
||||
// through auth.js's implicit mapping, which works on first
|
||||
// sign-in but isn't reliable after update() — once the update
|
||||
// path overrides token.name, the read-back path needs token
|
||||
// to be the authoritative source. Setting them explicitly
|
||||
// here keeps sign-in and update on the same path.
|
||||
if (typeof profile.name === "string") {
|
||||
token.name = profile.name;
|
||||
}
|
||||
if (typeof profile.email === "string") {
|
||||
token.email = profile.email;
|
||||
}
|
||||
// Pin token.sub to the OIDC subject. Auth.js v5 otherwise puts a
|
||||
// freshly generated UUID in token.sub on initial sign-in,
|
||||
// ignoring what profile() returns for `id`. That UUID then
|
||||
@@ -99,10 +117,19 @@ export const authConfig: NextAuthConfig = {
|
||||
async session({ session, token }) {
|
||||
const roles = (token.roles as Role[]) ?? [];
|
||||
const orgName = (token.orgName as string) ?? "";
|
||||
// Phase 6 fix5: read name and email directly from the token.
|
||||
// Previously this code relied on `session.user?.name`, expecting
|
||||
// auth.js to map token.name → session.user.name automatically.
|
||||
// That mapping is brittle: it works on first sign-in (because
|
||||
// OIDC profile() populates session.user) but not after update()
|
||||
// overrides token.name. Reading from token is the canonical
|
||||
// path regardless of how the token was last written.
|
||||
const tokenName = (token.name as string | undefined) ?? "";
|
||||
const tokenEmail = (token.email as string | undefined) ?? "";
|
||||
const sessionUser: SessionUser = {
|
||||
id: token.sub!,
|
||||
name: session.user?.name ?? "",
|
||||
email: session.user?.email ?? "",
|
||||
name: tokenName || session.user?.name || "",
|
||||
email: tokenEmail || session.user?.email || "",
|
||||
orgId: token.orgId as string,
|
||||
orgName,
|
||||
roles,
|
||||
@@ -115,6 +142,14 @@ export const authConfig: NextAuthConfig = {
|
||||
isPersonal: isPersonalOrgName(orgName),
|
||||
};
|
||||
(session as any).platformUser = sessionUser;
|
||||
// Also overwrite session.user so any client-side code that uses
|
||||
// the standard NextAuth shape (session.user.name) sees the new
|
||||
// value. Pre-fix5 code paths read from session.user.name; this
|
||||
// keeps them working without per-component changes.
|
||||
if (session.user) {
|
||||
session.user.name = sessionUser.name;
|
||||
session.user.email = sessionUser.email;
|
||||
}
|
||||
return session;
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user