🐈

Blitz.jsでGoogle OAuth 2.0を使ったログインを実装する

2021/03/15に公開

はじめに

本記事では、Blitz.jsにNext.jsのAPI機能とPassport.jsを使ってGoogleGoogle Oauth 2.0を使ったログインを実装します!

Blitz.jsで認証はどうなってるのか

Blitz.jsでは、blitz newでプロジェクト生成した時点でメールアドレスでの認証とセッション管理が生成されています。すごい

Blitz.jsのセッション管理では、SuperToknesと同じアプローチを採用しているらしく、SuperTokensのCTOであるRishabh Poddar氏が監修をしているらしい。

そしてBlitz.jsにはPssport.jsというNode.jsの認証ミドルウェアのStrategyと呼ばれるプラグイン的な物でverifyコールバックを使用するものをサポートしています。

Passport.jsのサイトで500以上のStrategyを探すことができる
http://www.passportjs.org/packages/

↓SuperTokensのトップページにBlitz.js作者が載ってた

Googleの認証情報を作る


Google Cloud Platformの「APIとサービス」から認証情報の画面で
認証情報の作成→OAuthクライアントID

アプリケーションの種類をWebにして名前をつける

  • リクエストのホワイトリストにhttp://localhost:3000
  • リダイレクトURIにhttp://localhost:3000/api/auth/google/callback
    などを追加する

そして、生成されてたクライアントIDとクライアントシークレットを.env.localに入れる

GOOGLE_CLIENT_ID="クライアントID"
GOOGLE_CLIENT_SECRET="クライアントシークレット"

Passport.jsを使ってGoogleログインを実装する

passport.jsのGoogle OAuth 2.0 Strategyを使う

yarn add passport-google-oauth20

https://github.com/mstade/passport-google-oauth2

Blitz.jsでは app/api/auth/[...auth].tsを作ると

  • /api/auth/[strategyName] がログインを開始するためのURL
  • /api/auth/[strategyName]/callback が先ほどGCPで指定したコールバックURL
    となる2つのルーティング設定が生成される。賢い

今回の場合、/api/auth/google にアクセスするとGoogleのログイン画面に遷移するようになる

また、blitz newで生成されるUser modelに今回はGoogleから取得するアイコン画像を加えるためにモデルを更新します

blitz generate model User icon:string
app/api/auth/[...auth].ts
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"
              ? "デプロイ先/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 })
        }
      ),
    },
  ],
})

これだけGoogleログインが実装できました!Blitz.jsすごい

試してみる

  • TOPページのログインボタンを/api/auth/googleへのLinkに変えてユーザー名を表示するようにする
  • <img src={currentUser.icon} alt="user-icon" />でアイコン画像を表示してみる
app/pages/index.tsx
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>
      </>
    )
  }
}

作成したログインボタンから任意のGoogleアカウントでログインすることができ、ユーザー名とアイコン画像を表示することができました。

Blitz.jsはすごい

4月に正式リリースするらしいので楽しみ
https://blitzjs.com/

Discussion