iTranslated by AI
Implementing Google OAuth 2.0 Login with Blitz.js
Introduction
In this article, we will implement login using Google OAuth 2.0 in Blitz.js by leveraging Next.js API functions and Passport.js!
How Authentication Works in Blitz.js
In Blitz.js, when you generate a project with blitz new, email-based authentication and session management are already generated. Amazing.
For session management, Blitz.js seemingly adopts the same approach as SuperTokens, and it is said to be supervised by Rishabh Poddar, the CTO of SuperTokens.
Furthermore, Blitz.js supports the use of verify callbacks with Passport.js—a Node.js authentication middleware—using its plugin-like system called "Strategies."
You can find over 500 strategies on the Passport.js website:
↓ The author of Blitz.js was featured on the SuperTokens homepage:
Creating Google Credentials
Go to the "Credentials" screen under "APIs & Services" in the Google Cloud Platform console.
Click Create Credentials -> OAuth client ID
Set the application type to "Web application" and give it a name.
- Add http://localhost:3000 to the Authorized JavaScript origins.
- Add http://localhost:3000/api/auth/google/callback (or similar) to the Authorized redirect URIs.
Finally, add the generated Client ID and Client Secret to your .env.local file.
GOOGLE_CLIENT_ID="Your Client ID"
GOOGLE_CLIENT_SECRET="Your Client Secret"
Implementing Google Login Using Passport.js
We will use the Google OAuth 2.0 Strategy for Passport.js.
yarn add passport-google-oauth20
In Blitz.js, creating app/api/auth/[...auth].ts generates two routing configurations:
-
/api/auth/[strategyName]is the URL to start the login process. -
/api/auth/[strategyName]/callbackis the callback URL specified earlier in GCP.
Very clever.
In this case, accessing /api/auth/google will redirect you to the Google login screen.
Also, we will update the User model generated by blitz new to include an icon image retrieved from Google.
blitz generate model User icon:string
import { passportAuth } from "blitz"
import db from "db"
import { Strategy as GoogleStrategy } from "passport-google-oauth20"
export default passportAuth({
successRedirectUrl: "/",
errorRedirectUrl: "/",
strategies: [
{
strategy: new GoogleStrategy(
{
clientID: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
callbackURL:
process.env.NODE_ENV === "production"
? "deployment-url/api/auth/google/callback"
: "http://localhost:3000/api/auth/google/callback",
scope: ["email", "profile"],
},
async function (_token, _tokenSecret, profile, done) {
const email = profile.emails && profile.emails[0]?.value
const user = await db.user.upsert({
where: { email },
create: {
email,
name: profile.displayName,
icon: profile.photos[0]?.value,
},
update: { email },
})
const publicData = {
userId: user.id,
roles: [user.role],
source: "google",
}
done(null, { publicData })
}
),
},
],
})
With just this, Google login is implemented! Blitz.js is amazing.
Let's try it out
- Change the login button on the top page to a
Linkto/api/auth/googleand make it display the username. - Try displaying the icon image with
<img src={currentUser.icon} alt="user-icon" />.
const UserInfo = () => {
const currentUser = useCurrentUser()
const [logoutMutation] = useMutation(logout)
if (currentUser) {
return (
<>
<button
className="button small"
onClick={async () => {
await logoutMutation()
}}
>
Logout
</button>
<div>
User id: <code>{currentUser.id}</code>
<br />
User role: <code>{currentUser.role}</code>
+ <br />
+ User name: <code>{currentUser.name}</code>
+ <img src={currentUser.icon} alt="user-icon" />
</div>
</>
)
} else {
return (
<>
<Link href="/signup">
<a className="button small">
<strong>Sign Up</strong>
</a>
</Link>
<Link href="/api/auth/google">
<a className="button small">
<strong>Log In With Google</strong>
</a>
</Link>
</>
)
}
}
I was able to log in with an arbitrary Google account using the created login button and display the username and icon image.
Blitz.js is Amazing
It seems the official release is in April, so I'm looking forward to it.
Discussion