mirror of
https://github.com/sourcebot-dev/sourcebot.git
synced 2025-12-12 04:15:30 +00:00
wip on updating access_token
This commit is contained in:
parent
cbc2cfc190
commit
d022066529
2 changed files with 114 additions and 77 deletions
|
|
@ -29,9 +29,20 @@ export const AuthMethodSelector = ({
|
||||||
// Call the optional analytics callback first
|
// Call the optional analytics callback first
|
||||||
onProviderClick?.(provider);
|
onProviderClick?.(provider);
|
||||||
|
|
||||||
signIn(provider, {
|
// @nocheckin
|
||||||
redirectTo: callbackUrl ?? "/"
|
signIn(
|
||||||
});
|
provider,
|
||||||
|
{
|
||||||
|
redirectTo: callbackUrl ?? "/",
|
||||||
|
},
|
||||||
|
// @see: https://github.com/nextauthjs/next-auth/issues/2066
|
||||||
|
// @see: https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
|
||||||
|
// @see: https://next-auth.js.org/getting-started/client#additional-parameters
|
||||||
|
{
|
||||||
|
prompt: 'consent',
|
||||||
|
scope: 'read:user user:email repo'
|
||||||
|
}
|
||||||
|
);
|
||||||
}, [callbackUrl, onProviderClick]);
|
}, [callbackUrl, onProviderClick]);
|
||||||
|
|
||||||
// Separate OAuth providers from special auth methods
|
// Separate OAuth providers from special auth methods
|
||||||
|
|
|
||||||
|
|
@ -60,88 +60,92 @@ export const getProviders = () => {
|
||||||
const providers: IdentityProvider[] = eeIdentityProviders;
|
const providers: IdentityProvider[] = eeIdentityProviders;
|
||||||
|
|
||||||
if (env.SMTP_CONNECTION_URL && env.EMAIL_FROM_ADDRESS && env.AUTH_EMAIL_CODE_LOGIN_ENABLED === 'true') {
|
if (env.SMTP_CONNECTION_URL && env.EMAIL_FROM_ADDRESS && env.AUTH_EMAIL_CODE_LOGIN_ENABLED === 'true') {
|
||||||
providers.push({ provider: EmailProvider({
|
providers.push({
|
||||||
server: env.SMTP_CONNECTION_URL,
|
provider: EmailProvider({
|
||||||
from: env.EMAIL_FROM_ADDRESS,
|
server: env.SMTP_CONNECTION_URL,
|
||||||
maxAge: 60 * 10,
|
from: env.EMAIL_FROM_ADDRESS,
|
||||||
generateVerificationToken: async () => {
|
maxAge: 60 * 10,
|
||||||
const token = String(Math.floor(100000 + Math.random() * 900000));
|
generateVerificationToken: async () => {
|
||||||
return token;
|
const token = String(Math.floor(100000 + Math.random() * 900000));
|
||||||
},
|
return token;
|
||||||
sendVerificationRequest: async ({ identifier, provider, token }) => {
|
},
|
||||||
const transport = createTransport(provider.server);
|
sendVerificationRequest: async ({ identifier, provider, token }) => {
|
||||||
const html = await render(MagicLinkEmail({ token: token }));
|
const transport = createTransport(provider.server);
|
||||||
const result = await transport.sendMail({
|
const html = await render(MagicLinkEmail({ token: token }));
|
||||||
to: identifier,
|
const result = await transport.sendMail({
|
||||||
from: provider.from,
|
to: identifier,
|
||||||
subject: 'Log in to Sourcebot',
|
from: provider.from,
|
||||||
html,
|
subject: 'Log in to Sourcebot',
|
||||||
text: `Log in to Sourcebot using this code: ${token}`
|
html,
|
||||||
});
|
text: `Log in to Sourcebot using this code: ${token}`
|
||||||
|
});
|
||||||
|
|
||||||
const failed = result.rejected.concat(result.pending).filter(Boolean);
|
const failed = result.rejected.concat(result.pending).filter(Boolean);
|
||||||
if (failed.length) {
|
if (failed.length) {
|
||||||
throw new Error(`Email(s) (${failed.join(", ")}) could not be sent`);
|
throw new Error(`Email(s) (${failed.join(", ")}) could not be sent`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}), purpose: "sso"
|
||||||
}), purpose: "sso"});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (env.AUTH_CREDENTIALS_LOGIN_ENABLED === 'true') {
|
if (env.AUTH_CREDENTIALS_LOGIN_ENABLED === 'true') {
|
||||||
providers.push({ provider: Credentials({
|
providers.push({
|
||||||
credentials: {
|
provider: Credentials({
|
||||||
email: {},
|
credentials: {
|
||||||
password: {}
|
email: {},
|
||||||
},
|
password: {}
|
||||||
type: "credentials",
|
},
|
||||||
authorize: async (credentials) => {
|
type: "credentials",
|
||||||
const body = verifyCredentialsRequestSchema.safeParse(credentials);
|
authorize: async (credentials) => {
|
||||||
if (!body.success) {
|
const body = verifyCredentialsRequestSchema.safeParse(credentials);
|
||||||
return null;
|
if (!body.success) {
|
||||||
}
|
return null;
|
||||||
const { email, password } = body.data;
|
}
|
||||||
|
const { email, password } = body.data;
|
||||||
|
|
||||||
const user = await prisma.user.findUnique({
|
const user = await prisma.user.findUnique({
|
||||||
where: { email }
|
where: { email }
|
||||||
});
|
|
||||||
|
|
||||||
// The user doesn't exist, so create a new one.
|
|
||||||
if (!user) {
|
|
||||||
const hashedPassword = bcrypt.hashSync(password, 10);
|
|
||||||
const newUser = await prisma.user.create({
|
|
||||||
data: {
|
|
||||||
email,
|
|
||||||
hashedPassword,
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const authJsUser: AuthJsUser = {
|
// The user doesn't exist, so create a new one.
|
||||||
id: newUser.id,
|
if (!user) {
|
||||||
email: newUser.email,
|
const hashedPassword = bcrypt.hashSync(password, 10);
|
||||||
|
const newUser = await prisma.user.create({
|
||||||
|
data: {
|
||||||
|
email,
|
||||||
|
hashedPassword,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const authJsUser: AuthJsUser = {
|
||||||
|
id: newUser.id,
|
||||||
|
email: newUser.email,
|
||||||
|
}
|
||||||
|
|
||||||
|
onCreateUser({ user: authJsUser });
|
||||||
|
return authJsUser;
|
||||||
|
|
||||||
|
// Otherwise, the user exists, so verify the password.
|
||||||
|
} else {
|
||||||
|
if (!user.hashedPassword) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bcrypt.compareSync(password, user.hashedPassword)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: user.id,
|
||||||
|
email: user.email,
|
||||||
|
name: user.name ?? undefined,
|
||||||
|
image: user.image ?? undefined,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onCreateUser({ user: authJsUser });
|
|
||||||
return authJsUser;
|
|
||||||
|
|
||||||
// Otherwise, the user exists, so verify the password.
|
|
||||||
} else {
|
|
||||||
if (!user.hashedPassword) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!bcrypt.compareSync(password, user.hashedPassword)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
id: user.id,
|
|
||||||
email: user.email,
|
|
||||||
name: user.name ?? undefined,
|
|
||||||
image: user.image ?? undefined,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}), purpose: "sso"
|
||||||
}), purpose: "sso"});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return providers;
|
return providers;
|
||||||
|
|
@ -156,7 +160,29 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
|
||||||
trustHost: true,
|
trustHost: true,
|
||||||
events: {
|
events: {
|
||||||
createUser: onCreateUser,
|
createUser: onCreateUser,
|
||||||
signIn: async ({ user }) => {
|
signIn: async ({ user, account }) => {
|
||||||
|
// Explicitly update the Account record with the OAuth token details.
|
||||||
|
// This is necessary to update the access token when the user
|
||||||
|
// re-authenticates.
|
||||||
|
if (account && account.provider && account.providerAccountId) {
|
||||||
|
await prisma.account.update({
|
||||||
|
where: {
|
||||||
|
provider_providerAccountId: {
|
||||||
|
provider: account.provider,
|
||||||
|
providerAccountId: account.providerAccountId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
refresh_token: account.refresh_token,
|
||||||
|
access_token: account.access_token,
|
||||||
|
expires_at: account.expires_at,
|
||||||
|
token_type: account.token_type,
|
||||||
|
scope: account.scope,
|
||||||
|
id_token: account.id_token,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (user.id) {
|
if (user.id) {
|
||||||
await auditService.createAudit({
|
await auditService.createAudit({
|
||||||
action: "user.signed_in",
|
action: "user.signed_in",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue