Chris Padilla/Blog
My passion project! Posts spanning music, art, software, books, and more
You can follow by Newsletter or RSS! (What's RSS?) Full archive here.
Pachabel - Canon in D
An oldie, but a goodie.
I'm really tempted to run this video through a green screen effect! We could launch this video INTO SPAAAACE!
American Football
Been listening to lots of American Football and Midwest Emo lately.
My favorite rendition of their music has to be this Super Mario 64 soundfont cover.
Also, playoff season babyyy!!
Setting Up OAuth and Email Providers for Next Authentication
Continuing the journey of setting up Authentication with Next.js! Last time I walked through the email/password approach. I'll touch on setting up OAuth and email link sign in, mostly looking at how to coordinate multiple sign in providers for single user accounts.
Provider Setup
Email and OAuth setup is fairly straightforward and is best done as outlined in the docs.
One exception: I'm going to flip on allowDangerousEmailAccountLinking
in my email and OAuth provider settings
EmailProvider({
server: process.env.EMAIL_SERVER,
from: process.env.EMAIL_FROM,
allowDangerousEmailAccountLinking: true,
Reason being: our users are likely to use OAuth logins for one instance, but then be required to use email for other cases. By default, Next Auth won't link those separate logins with the same account. Here, we're able to do so without getting an error on login. I'll walk through handling account creation for existing users below:
Traffic Control
Much of the magic for customizing our login will happen in the signIn()
callback provided to our authOptions
callbacks: {
signIn: async ({user, account}) => {...},
}
Here, we'll have access to the user provided by our db adapter or from the OAuth provider.
Inside, I'll have a try / catch block handling different login cases:
try {
if(account?.provider === 'google') {
...
} else if(account.provider === 'credentials') {
...
} else if(account.provider === 'email') {
...
}
} catch (e) {
console.error(e);
}
I'll leave out explicit details for our particular application out, but I'll show how we're creating that account for OAuth login if the account does not already exist:
if(!foundUser) {
// User does not exist! Can't login
return false;
} else {
// User exists! We can log the user in
// Check if user account exists
const existingAccount = await db.collection('accounts').findOne({
...query
}, {
projection: {_id: 1},
});
// If no account exists, create it
if(!existingAccount) {
const accountObject = {
...account,
user: {
connect: {
email: user.email ?? '',
},
},
userId: foundUser._id,
};
const setRes = await db.collection('accounts').insertOne(accountObject);
if(!setRes.insertedId) {
throw new Error('Error saving new Google Provider Account into DB.');
}
}
return true;
}
So we've ensured next auth won't throw the error of an email already existing with another provider. Now, if the account doesn't already exist for this provider, we're ensuring there's not a lookup error by manually adding it ourselves.
Same logic works in the email provider flow.
From there, returning true
signals to Next Auth that the user can sign in safely.
Blue Monk
Transcribing after Charlie Rouse