Skip to content

Commit f362595

Browse files
wip on updating access_token
1 parent bb9fa4f commit f362595

File tree

2 files changed

+110
-73
lines changed

2 files changed

+110
-73
lines changed

packages/web/src/app/components/authMethodSelector.tsx

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,20 @@ export const AuthMethodSelector = ({
2929
// Call the optional analytics callback first
3030
onProviderClick?.(provider);
3131

32-
signIn(provider, {
33-
redirectTo: callbackUrl ?? "/"
34-
});
32+
// @nocheckin
33+
signIn(
34+
provider,
35+
{
36+
redirectTo: callbackUrl ?? "/",
37+
},
38+
// @see: https://github.com/nextauthjs/next-auth/issues/2066
39+
// @see: https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
40+
// @see: https://next-auth.js.org/getting-started/client#additional-parameters
41+
{
42+
prompt: 'consent',
43+
scope: 'read:user user:email repo'
44+
}
45+
);
3546
}, [callbackUrl, onProviderClick]);
3647

3748
// Separate OAuth providers from special auth methods

packages/web/src/auth.ts

Lines changed: 96 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -60,88 +60,92 @@ export const getProviders = () => {
6060
const providers: IdentityProvider[] = eeIdentityProviders;
6161

6262
if (env.SMTP_CONNECTION_URL && env.EMAIL_FROM_ADDRESS && env.AUTH_EMAIL_CODE_LOGIN_ENABLED === 'true') {
63-
providers.push({ provider: EmailProvider({
64-
server: env.SMTP_CONNECTION_URL,
65-
from: env.EMAIL_FROM_ADDRESS,
66-
maxAge: 60 * 10,
67-
generateVerificationToken: async () => {
68-
const token = String(Math.floor(100000 + Math.random() * 900000));
69-
return token;
70-
},
71-
sendVerificationRequest: async ({ identifier, provider, token }) => {
72-
const transport = createTransport(provider.server);
73-
const html = await render(MagicLinkEmail({ token: token }));
74-
const result = await transport.sendMail({
75-
to: identifier,
76-
from: provider.from,
77-
subject: 'Log in to Sourcebot',
78-
html,
79-
text: `Log in to Sourcebot using this code: ${token}`
80-
});
63+
providers.push({
64+
provider: EmailProvider({
65+
server: env.SMTP_CONNECTION_URL,
66+
from: env.EMAIL_FROM_ADDRESS,
67+
maxAge: 60 * 10,
68+
generateVerificationToken: async () => {
69+
const token = String(Math.floor(100000 + Math.random() * 900000));
70+
return token;
71+
},
72+
sendVerificationRequest: async ({ identifier, provider, token }) => {
73+
const transport = createTransport(provider.server);
74+
const html = await render(MagicLinkEmail({ token: token }));
75+
const result = await transport.sendMail({
76+
to: identifier,
77+
from: provider.from,
78+
subject: 'Log in to Sourcebot',
79+
html,
80+
text: `Log in to Sourcebot using this code: ${token}`
81+
});
8182

82-
const failed = result.rejected.concat(result.pending).filter(Boolean);
83-
if (failed.length) {
84-
throw new Error(`Email(s) (${failed.join(", ")}) could not be sent`);
83+
const failed = result.rejected.concat(result.pending).filter(Boolean);
84+
if (failed.length) {
85+
throw new Error(`Email(s) (${failed.join(", ")}) could not be sent`);
86+
}
8587
}
86-
}
87-
}), purpose: "sso"});
88+
}), purpose: "sso"
89+
});
8890
}
8991

9092
if (env.AUTH_CREDENTIALS_LOGIN_ENABLED === 'true') {
91-
providers.push({ provider: Credentials({
92-
credentials: {
93-
email: {},
94-
password: {}
95-
},
96-
type: "credentials",
97-
authorize: async (credentials) => {
98-
const body = verifyCredentialsRequestSchema.safeParse(credentials);
99-
if (!body.success) {
100-
return null;
101-
}
102-
const { email, password } = body.data;
93+
providers.push({
94+
provider: Credentials({
95+
credentials: {
96+
email: {},
97+
password: {}
98+
},
99+
type: "credentials",
100+
authorize: async (credentials) => {
101+
const body = verifyCredentialsRequestSchema.safeParse(credentials);
102+
if (!body.success) {
103+
return null;
104+
}
105+
const { email, password } = body.data;
103106

104-
const user = await prisma.user.findUnique({
105-
where: { email }
106-
});
107+
const user = await prisma.user.findUnique({
108+
where: { email }
109+
});
110+
111+
// The user doesn't exist, so create a new one.
112+
if (!user) {
113+
const hashedPassword = bcrypt.hashSync(password, 10);
114+
const newUser = await prisma.user.create({
115+
data: {
116+
email,
117+
hashedPassword,
118+
}
119+
});
107120

108-
// The user doesn't exist, so create a new one.
109-
if (!user) {
110-
const hashedPassword = bcrypt.hashSync(password, 10);
111-
const newUser = await prisma.user.create({
112-
data: {
113-
email,
114-
hashedPassword,
121+
const authJsUser: AuthJsUser = {
122+
id: newUser.id,
123+
email: newUser.email,
115124
}
116-
});
117125

118-
const authJsUser: AuthJsUser = {
119-
id: newUser.id,
120-
email: newUser.email,
121-
}
126+
onCreateUser({ user: authJsUser });
127+
return authJsUser;
122128

123-
onCreateUser({ user: authJsUser });
124-
return authJsUser;
129+
// Otherwise, the user exists, so verify the password.
130+
} else {
131+
if (!user.hashedPassword) {
132+
return null;
133+
}
125134

126-
// Otherwise, the user exists, so verify the password.
127-
} else {
128-
if (!user.hashedPassword) {
129-
return null;
130-
}
135+
if (!bcrypt.compareSync(password, user.hashedPassword)) {
136+
return null;
137+
}
131138

132-
if (!bcrypt.compareSync(password, user.hashedPassword)) {
133-
return null;
139+
return {
140+
id: user.id,
141+
email: user.email,
142+
name: user.name ?? undefined,
143+
image: user.image ?? undefined,
144+
};
134145
}
135-
136-
return {
137-
id: user.id,
138-
email: user.email,
139-
name: user.name ?? undefined,
140-
image: user.image ?? undefined,
141-
};
142146
}
143-
}
144-
}), purpose: "sso"});
147+
}), purpose: "sso"
148+
});
145149
}
146150

147151
return providers;
@@ -156,7 +160,29 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
156160
trustHost: true,
157161
events: {
158162
createUser: onCreateUser,
159-
signIn: async ({ user }) => {
163+
signIn: async ({ user, account }) => {
164+
// Explicitly update the Account record with the OAuth token details.
165+
// This is necessary to update the access token when the user
166+
// re-authenticates.
167+
if (account && account.provider && account.providerAccountId) {
168+
await prisma.account.update({
169+
where: {
170+
provider_providerAccountId: {
171+
provider: account.provider,
172+
providerAccountId: account.providerAccountId,
173+
},
174+
},
175+
data: {
176+
refresh_token: account.refresh_token,
177+
access_token: account.access_token,
178+
expires_at: account.expires_at,
179+
token_type: account.token_type,
180+
scope: account.scope,
181+
id_token: account.id_token,
182+
}
183+
})
184+
}
185+
160186
if (user.id) {
161187
await auditService.createAudit({
162188
action: "user.signed_in",
@@ -225,7 +251,7 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
225251
// Propagate the userId to the session.
226252
id: token.userId,
227253
}
228-
254+
229255
// Pass only linked account provider errors to the session (not sensitive tokens)
230256
if (token.linkedAccountTokens) {
231257
const errors: Record<string, string> = {};

0 commit comments

Comments
 (0)