How to properly add Google Sign In to existing application that has email login implemented already?

Hi, In my app I already have a working login system for email + password sign in. Now I would like to add Google Sign in as well. I already managed to allow user sign in with google but I wonder how I can properly handle user creation in the database in regards to username. Here is what my user model looks like:
model User {
id String @id @default(cuid())
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
username String @unique
email String @unique
passwordHash String @map("password_hash")
ratings Rating[]
favoriteEpisodes Episode[]
resetPasswordTokens ResetPasswordToken[]
changeEmailTokens ChangeEmailToken[]
}
model User {
id String @id @default(cuid())
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
username String @unique
email String @unique
passwordHash String @map("password_hash")
ratings Rating[]
favoriteEpisodes Episode[]
resetPasswordTokens ResetPasswordToken[]
changeEmailTokens ChangeEmailToken[]
}
The problem is that I somehow need to ask my user what username he wants. How can I do that? Maybe create a temporary Google Sign In User and then redirect the user after sign up and let him set the username? What kind of data model is suggested there?
Solution:
Hey! 👋 For Google Sign-In, you can't get a unique username directly from Google. Here's the deal: Make username optional: In your User database model, allow the username field to be null at first. Also add a googleId field (unique) to link accounts. A isCompletedProfile flag is helpful too. Google Sign-In: Frontend handles the Google login flow. Backend verifies the token from Google (super important!), then gets the user's Google ID (sub) and email....
Jump to solution
2 Replies
Solution
Jakov
Jakov4w ago
Hey! 👋 For Google Sign-In, you can't get a unique username directly from Google. Here's the deal: Make username optional: In your User database model, allow the username field to be null at first. Also add a googleId field (unique) to link accounts. A isCompletedProfile flag is helpful too. Google Sign-In: Frontend handles the Google login flow. Backend verifies the token from Google (super important!), then gets the user's Google ID (sub) and email. Check Existing: Look for a user in your DB by googleId first. If found, they're logged in! If not, check by email. If found by email, link the accounts (ask the user!). New User: If no user is found, create a new user record in your DB, but without a username yet. Set isCompletedProfile to false. Force Username Choice: After Google Sign-In (or account linking), if isCompletedProfile is false, immediately redirect the user to a "Choose Username" page. They must pick one before using your app. Username Validation: On that page, validate the username (length, characters, uniqueness – check against your DB!). Provide real-time availability feedback if you can (use debouncing!). Update & Finish: Once a valid username is chosen, update the user record in your DB, set isCompletedProfile to true, and redirect them to the main app. They're all set! Basically, you're separating authentication (Google handles that) from profile setup (you handle the username). 👍
Clemens
ClemensOP4w ago
Thank you so much for your detailed answer! I did something similar that seems to work but after thinking about it, there are some more questions:
Backend verifies the token from Google (super important!), then gets the user's Google ID (sub) and email.
I'm using the t3 Stack with NextAuth preconfigured. I assume that NextAuth does the verification automatically, right?
Also add a googleId field (unique) to link accounts
Interesting, I completely forgot to think about what happens when a users google email changes. I simply took the email address as identifier for google users but now that Im googling a bit it seems that this can change. Will use a googleId as suggested 👍 Do you usually need to handle if the Google users email changes? I think I simply won't handle that for the time being in my small web app but that seems like something I could do in the future. Like you said I now redirect the google users after first sign in to a username setting page. In the backend I set up specific protected procedures to make sure Google Sign In users can not do stuff like changing email, address, setting a password and so on. And I also use the protected procedure to stop email sign in users from setting a username. Looks like this:
export const providerProtectedProcedure = (provider: AuthProvider) => {
return protectedProcedure.use(({ ctx, next }) => {
if (ctx.session?.user.provider !== provider) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: `This endpoint requires authentication with ${provider} provider`,
});
}
return next({ ctx });
});
};
export const providerProtectedProcedure = (provider: AuthProvider) => {
return protectedProcedure.use(({ ctx, next }) => {
if (ctx.session?.user.provider !== provider) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: `This endpoint requires authentication with ${provider} provider`,
});
}
return next({ ctx });
});
};

Did you find this page helpful?