言語を切り替える
テーマを切り替える

Next.js OAuth ログイン実践:Google、GitHub、WeChat サードパーティログイン手とり足とりガイド

先週、コミュニティプロジェクトを引き受けた際、プロダクトマネージャーから一言「Google ログイン追加しておいて、すぐ終わるでしょ」と言われました。サードパーティログインなんていくつかチュートリアル読んだことあるし、30分で終わるだろうと思っていました。しかし結果は、午後の全てを費やし、redirect_uri エラーや token 取得失敗に悩まされ、コンソールは赤いエラーメッセージだらけ。一番心が折れたのは、公式ドキュメント通りにやっているはずなのに動かないことでした。

後で気付いたのですが、問題はコードではなく、私が OAuth のフローを浅くしか理解していなかったことでした。authorization code、access token、callback といった概念は、単体では分かっても、組み合わせると混乱します。もしあなたがサードパーティログインに苦戦している、あるいは Next.js プロジェクトにログイン機能を追加しようとしているなら、この記事が役立つはずです。

今回は OAuth フローを専門用語を並べる RFC ドキュメントのような抽象的な説明ではなく、「代理で荷物を受け取る」という生活のシーンに例えて、平易な言葉で解説します。なぜ code と token の2つが必要なのか、callback は何をしているのか、そして設定で間違いやすいポイントが分かります。その上で、Google(国際標準)、GitHub(開発者向け)、WeChat(国内必須だが面倒)の3つのログイン設定を手とり足とりガイドします。

正直、WeChat ログインは一番厄介です。ドキュメントが不親切で、企業資格が必要で、ローカルデバッグも面倒です。しかし国内プロジェクトでは避けられない道なので、内網穿透(イントラネット貫通)でのデバッグ方法や、カスタム Provider の設定など、私が踏んだ地雷をすべて共有します。これを読めば、国内外のログイン要件をワンセットのコードアーキテクチャで解決できるようになるはずです。

OAuth フローとは一体何か

代理荷物受取で理解する OAuth

私が初めて OAuth に触れた時、authorization code や access token という概念に頭を抱えました。後になって、これは代理で荷物を受け取るロジックと同じだと理解しました。

想像してください:配送センターにあなたの荷物(ユーザー情報)がありますが、あなたは会社にいて自分で取りに行けません。そこで友人(あなたの Next.js アプリ)に代わりに取りに行ってもらうことにしました。配送センターは誰にでも荷物を渡すわけにはいかないので、あなたの許可が必要です。フローはこうなります:

1. あなたが友人に受取コードを渡す - これが authorization code です。「Google でログイン」ボタンをクリックすると、Google の認可ページに飛び、同意すると、Google は一時的な code を生成し、URL パラメータとしてあなたのアプリに渡します。

2. 友人が受取コードを持って配送センターへ行く - これがアプリのバックエンドが code を使って access token と交換する部分です。しかし配送センターは、この友人が本当に信頼できる人か確認するため、友人の身分証番号(client_secret)を事前に登録しておく必要があります。

3. 本人確認後に荷物を渡す - 配送センターは受取コードと身分証番号が正しいことを確認し、荷物(ユーザー情報)を友人に渡し、友人がそれをあなたに渡します。これが access_token を使ってユーザー情報を取得するプロセスです。

重要なのはここです:受取コード(code)は使い捨てで、誰に見られても(身分証番号である secret とセットでないと)配送センターは荷物を渡さないため、無意味です。だから code はブラウザの URL で平文で送信でき、secret はバックエンドに隠しておく必要があるのです。

4つの主要ステップの分解

技術的なフローに落とし込むと、この4ステップになります:

ステップ1:OAuth サーバーの認可ページへジャンプ

ユーザーが「Google でログイン」をクリックすると、フロントエンドは URL を構築し、ユーザーを Google にリダイレクトします:

https://accounts.google.com/o/oauth2/v2/auth?
  client_id=あなたのアプリID
  &redirect_uri=http://localhost:3000/api/auth/callback/google
  &response_type=code
  &scope=email profile

ここのパラメータ:

  • client_id:Google におけるあなたのアプリの身分証
  • redirect_uri:Google が認可後にユーザーを送り返す場所
  • scope:アクセスしたいユーザー情報の範囲

ステップ2:ユーザーが認可に同意し、code を取得

ユーザーが Google ページで「許可」をクリックすると、Google はあなたのアプリにリダイレクトして戻します。URL はこうなります:

http://localhost:3000/api/auth/callback/google?code=4/0AfJohXl...&state=random123

この code が受取コードです。有効期限は非常に短く、通常5-10分のみ、かつ一度しか使えません。

ステップ3:バックエンドで code を access_token に交換

あなたのアプリのバックエンド(注意:バックエンドです。フロントエンドではありません)が code と client_secret を持って、Google にリクエストを送ります:

const response = await fetch('https://oauth2.googleapis.com/token', {
  method: 'POST',
  body: JSON.stringify({
    code: 'さっき取得したcode',
    client_id: 'your_client_id',
    client_secret: 'your_secret', // これは絶対にフロントエンドに露出してはいけない
    redirect_uri: 'http://localhost:3000/api/auth/callback/google',
    grant_type: 'authorization_code'
  })
})

const { access_token } = await response.json()

access_token を取得して初めて、ユーザー情報を取得する鍵を手に入れたことになります。

ステップ4:access_token でユーザー情報を取得

token があれば、Google の API を叩いてユーザーデータを取得できます:

const userInfo = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
  headers: {
    Authorization: `Bearer ${access_token}`
  }
})

const user = await userInfo.json()
// { email: "user@gmail.com", name: "田中太郎", picture: "アイコンURL" }

ユーザー情報を取得したら、自分のデータベースでユーザーレコードを作成または更新し、セッションを生成してログイン完了です。

主要概念クイックリファレンス表

よくある用語を整理しました。対照表として使ってください:

用語平易な解説どこで見られるか
Client IDアプリの身分証番号、公開OK.env.localファイル、ブラウザURLパラメータ
Client Secretアプリのパスワード、絶対秘密バックエンドコードと環境変数の中だけ
Authorization Code使い捨て受取コードコールバックURLのcodeパラメータ
Access Token情報を取得できる真の鍵バックエンドコード内、フロントには渡さない
Redirect URI認可後の戻り先アドレスOAuthアプリ設定、認可URLパラメータ
Scopeアクセス権限の範囲認可URLパラメータ、例:“email profile”
StateCSRF攻撃防止用ランダム文字列認可URLパラメータとコールバックURLパラメータ

Stateパラメータの役割:認可開始時にランダムな文字列(例:“abc123”)を生成し、セッションに保存すると同時に OAuth サーバーへ送ります。コールバック時に戻ってきた state が “abc123” か確認します。もし違えば、攻撃された可能性があるので拒否します。NextAuth.js はこれを自動処理してくれます。

なぜ直接 token を返さないのか?

最終的に access_token が欲しいなら、なぜ URL で直接 token を返さず、わざわざ code を交換する手間をかけるのか?

セキュリティのためです。

ブラウザのアドレスバーの URL は平文であり、ブラウザ履歴、サーバーログ、ブラウザプラグインから見えてしまいます。もし token を直接返すと、ユーザー情報の鍵を平文でばら撒くことになり、リスクが高すぎます。

一方 code は盗まれても無意味です。なぜなら:

  1. Code は一度しか使えず、使えば無効になる
  2. Token 交換には client_secret が必要だが、これはバックエンドしか知らない
  3. OAuth サーバーは redirect_uri が一致するかも検証する

これなら攻撃者が code を傍受しても、secret がなければ token に変えられず、ユーザー情報は安全です。

この設計は「Authorization Code Flow」と呼ばれ、OAuth 2.0 で最も安全な認可方式で、バックエンドサーバーを持つ Web アプリに最適です。「Implicit Flow」という直接 token を返す方式もありますが、安全性の問題から現在は非推奨です。

NextAuth.js クイックスタート

なぜ NextAuth.js なのか

Next.js の OAuth ログイン実装には、完全手書きとライブラリ利用の2通りがあります。私は手書きを試みて無数の落とし穴にはまり、潔く降参して NextAuth.js に切り替えました。

おすすめする理由:

理由1:公式のお墨付き、成熟したエコシステム

NextAuth.js は Next.js 公式ドキュメントで推奨されている認証ソリューションで、GitHub で 7万以上のスターを持ち、メンテナンスも活発です。2024年11月にリリースされた v5 バージョンは App Router と Server Components を完全にサポートしており、互換性の心配はありません。

理由2:30以上の OAuth プロバイダー内蔵

Google、GitHub、Facebook、Twitter など一般的なものは設定数行ですぐ動きます。WeChat のように内蔵されていないものも、カスタム Provider メカニズムがあり、ゼロから OAuth フローを書く必要はありません。

理由3:複雑なロジックの自動処理

セッション管理、JWT 署名、データベース保存、CSRF 保護などを全自動でやってくれます。あなたは「ユーザーの初回ログイン時にウェルカムメールを送るかどうか」といったビジネスロジックに集中できます。

コア設定ファイルの構造

NextAuth.js の核心は API route です。App Router (Next.js 13+) を使用している場合、ファイルパスは:

app/api/auth/[...nextauth]/route.ts

この [...nextauth] は Next.js の catch-all route で、/api/auth/* への全てのリクエストをこのファイルで処理することを意味します。例えば:

  • /api/auth/signin - ログインページ
  • /api/auth/callback/google - Google コールバック
  • /api/auth/signout - ログアウト
  • /api/auth/session - 現在のセッション取得

基本設定はこんな感じです:

// app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth"
import GoogleProvider from "next-auth/providers/google"
import GitHubProvider from "next-auth/providers/github"

export const authOptions = {
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    }),
    GitHubProvider({
      clientId: process.env.GITHUB_ID!,
      clientSecret: process.env.GITHUB_SECRET!,
    }),
  ],
  // オプション:カスタムログインページ
  pages: {
    signIn: '/login',
  },
  // オプション:コールバック関数、ログイン後のロジック処理
  callbacks: {
    async signIn({ user, account, profile }) {
      // ユーザーがホワイトリストにいるかチェックなど
      return true // false を返すとログイン阻止
    },
    async session({ session, token }) {
      // セッションに追加情報を付与
      session.user.id = token.sub
      return session
    },
  },
}

const handler = NextAuth(authOptions)
export { handler as GET, handler as POST }

最後の行 export { handler as GET, handler as POST } は重要です。App Router は HTTP メソッドのハンドラを明示的にエクスポートする必要があります。

環境変数の命名規則

NextAuth.js、特に v5 バージョンは環境変数の命名に少しこだわりがあります:

必須の環境変数

# .env.local

# NextAuth設定
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=your-secret-key-here

# または新しい命名(v5推奨)
AUTH_SECRET=your-secret-key-here

# Google OAuth
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret

# または AUTH_ 接頭辞(v5自動認識)
AUTH_GOOGLE_ID=your-google-client-id
AUTH_GOOGLE_SECRET=your-google-client-secret

# GitHub OAuth
GITHUB_ID=your-github-client-id
GITHUB_SECRET=your-github-client-secret

# または
AUTH_GITHUB_ID=your-github-client-id
AUTH_GITHUB_SECRET=your-github-client-secret

いくつかの重要ポイント

  1. NEXTAUTH_URL:アプリの完全な URL。開発環境は http://localhost:3000、本番環境は実際のドメイン(https含む)である必要があります。

  2. NEXTAUTH_SECRET / AUTH_SECRET:JWT 署名用キー。ランダムな文字列である必要があります。生成方法:

openssl rand -base64 32

これは絶対に漏洩させず、Git にもコミットしないでください。漏洩したら即座に変更してください。さもないとセッションを偽造されます。

  1. AUTH_ 接頭辞の魔法:NextAuth.js v5 は AUTH_PROVIDER_IDAUTH_PROVIDER_SECRET 形式の変数を自動認識するため、コード内で process.env.XXX と書く必要がなくなり便利です。

インストールと最小構成

長々と話しましたが、着手は簡単です:

ステップ1:インストール

npm install next-auth
# または
pnpm add next-auth

ステップ2:API route 作成

app/api/auth/[...nextauth]/route.ts を作成し、先ほどのコードを貼り付けます。

ステップ3:.env.local 作成

NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=openssl rand -base64 32 で生成した文字列

ステップ4:フロントエンドにログインボタン追加

// app/login/page.tsx
'use client'

import { signIn } from 'next-auth/react'

export default function LoginPage() {
  return (
    <div>
      <button onClick={() => signIn('google')}>
        Googleでログイン
      </button>
      <button onClick={() => signIn('github')}>
        GitHubでログイン
      </button>
    </div>
  )
}

ステップ5:Provider でアプリをラップ

クライアントコンポーネントで useSession() を使うなら、Provider が必要です:

// app/layout.tsx
import { SessionProvider } from 'next-auth/react'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <SessionProvider>
          {children}
        </SessionProvider>
      </body>
    </html>
  )
}

これらの設定で基本骨格は完成です。もちろん今はログインボタンを押してもエラーになります。Google と GitHub の OAuth アプリ設定がまだだからです。次はそれをやります。

Google ログイン実践設定

Google Cloud Console 設定

Google OAuth 設定は2部分あります:Google Cloud Console での OAuth アプリ作成と、Next.js での連携です。

ステップ1:Google Cloud Console へ

https://console.cloud.google.com にアクセスし、Google アカウントでログイン。初めてならプロジェクト作成を求められるので、適当な名前(例:「私のブログ」)で作ります。

ステップ2:Google+ API の有効化

Google+ は終了しましたが、OAuth はまだこの API に依存しています。左側メニュー「APIs & Services」→「Library」で「Google+ API」を検索し、有効化(Enable)します。

ステップ3:OAuth 認証情報作成

  • 左側「Credentials」
  • 上部「Create Credentials」→「OAuth client ID」
  • 初回は「OAuth consent screen」設定を求められます。アプリ名、サポートメールを入力し、他はスキップでOK。
  • Application type は「Web application」
  • Name は適当に、例:「Next.js App」

ステップ4:Redirect URIs の設定(最重要)

これが最もエラーになりやすい箇所です。Authorized redirect URIs に2つ入力します:

開発環境:

http://localhost:3000/api/auth/callback/google

本番環境(デプロイ後に追加):

https://yourdomain.com/api/auth/callback/google

注意点:

  • http vs https:ローカルは http、本番は https 必須。Google は本番での http を許可しません。
  • ポート番号:ローカルが 3001 なら localhost:3001 と書く。省略不可。
  • パス:/api/auth/callback/google 一文字も間違えてはいけません。スラッシュの過不足もダメ。
  • クエリパラメータは不要:/google まででOK。後ろの ?code=xxx は Google が自動付与します。

「Create」をクリックし、Client ID と Client Secret をコピーして保存します。

ステップ5:.env.local にコピー

GOOGLE_CLIENT_ID=あなたのClient ID.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOCSPX-xxxxxxxxxxxx

Next.js コード統合

NextAuth.js 設定には既に GoogleProvider を入れたので、環境変数が正しければ動きます。少し最適化してみましょう:

// app/api/auth/[...nextauth]/route.ts
import GoogleProvider from "next-auth/providers/google"

export const authOptions = {
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
      authorization: {
        params: {
          prompt: "consent",
          access_type: "offline",
          response_type: "code"
        }
      }
    }),
  ],
}

authorization.params を追加しました:

  • prompt: "consent":ログインの度に認可画面を表示(テストに便利。本番は外せばユーザーの選択を記憶します)
  • access_type: "offline":refresh token を返します。ユーザーがオフラインでも token を更新できます(長期アクセスが必要な場合に追加)
  • response_type: "code":authorization code flow を明示

ログインフローのテスト

Next.js を起動:

npm run dev

http://localhost:3000/login にアクセスし、「Googleでログイン」をクリック。Google 認可ページに飛び、許可するとアプリに戻ります。

任意のページでセッション取得:

// app/page.tsx
import { getServerSession } from "next-auth"
import { authOptions } from "./api/auth/[...nextauth]/route"

export default async function Home() {
  const session = await getServerSession(authOptions)

  if (session) {
    return <div>こんにちは, {session.user?.name}</div>
  }

  return <div>未ログイン</div>
}

またはクライアントコンポーネントで:

'use client'
import { useSession } from "next-auth/react"

export default function Profile() {
  const { data: session, status } = useSession()

  if (status === "loading") return <div>読み込み中...</div>
  if (!session) return <div>未ログイン</div>

  return (
    <div>
      <img src={session.user?.image} alt="アイコン" />
      <p>{session.user?.name}</p>
      <p>{session.user?.email}</p>
    </div>
  )
}

よくあるエラー排查

エラー1:redirect_uri_mismatch

完全なエラー:

Error 400: redirect_uri_mismatch
The redirect URI in the request, http://localhost:3000/api/auth/callback/google,
does not match the ones authorized for the OAuth client.

原因:Google Console で設定した URI と実際の callback URI が完全一致していません。

手順:

  1. ブラウザ開発者ツール → Network タブ
  2. ログインボタンを押して Google に飛ぶ際のリクエストを見る
  3. redirect_uri パラメータの値をコピー
  4. Google Console の Authorized redirect URIs に一字一句違わず貼り付ける
  5. プロトコル(http/https)、ポート、パス、スラッシュを確認

エラー2:Access blocked: This app’s request is invalid

OAuth consent screen が未設定か、テストユーザー未追加です。

解決:

  • Google Console → “OAuth consent screen”
  • User Type を “External”(外部公開)または “Internal”(企業内)に
  • アプリ情報を入力
  • External かつ未公開の場合、“Test users” にテストアカウントのメールを追加

エラー3:ポート番号問題

ローカル開発で localhost:3001 で動かしているのに redirect URI が localhost:3000 だとエラーになります。

簡単策:統一して 3000 を使うか、Google Console に複数の redirect URI(3000、3001、3002)を追加しておく。

エラー4:HTTPS 必須

本番環境デプロイ後、ドメインが http だと Google は拒否します。必ず https にしてください。Vercel や Netlify なら自動で https になるので心配無用です。

GitHub ログイン設定

GitHub OAuth App 設定

GitHub の設定は Google より簡単で、API 有効化不要、OAuth App 作成だけです。

ステップ1:Developer settings へ

GitHub ログイン → 右上アイコン → Settings → 左下 Developer settings → OAuth Apps → New OAuth App。

ステップ2:アプリ情報入力

  • Application name:適当に。ユーザーには見えません
  • Homepage URL:ローカルなら http://localhost:3000、本番ならドメイン
  • Authorization callback URLhttp://localhost:3000/api/auth/callback/github

GitHub の callback URL は柔軟で、後から変更も容易です。Google ほど厳格ではありません。

Register application を押し、Client ID を取得。「Generate a new client secret」で使用 Secret を生成(一回しか表示されないので保存必須)。

ステップ3:.env.local にコピー

GITHUB_ID=你的Client ID
GITHUB_SECRET=你的Client Secret

Next.js 統合

NextAuth.js 設定:

import GitHubProvider from "next-auth/providers/github"

export const authOptions = {
  providers: [
    GitHubProvider({
      clientId: process.env.GITHUB_ID!,
      clientSecret: process.env.GITHUB_SECRET!,
    }),
  ],
}

これだけです。追加設定は不要。

GitHub vs Google の違い

比較項目GoogleGitHub
設定難易度中、API 有効化が必要簡単、作成するだけ
Redirect URI厳格、完全一致必須柔軟、ワイルドカード可
HTTPS 要求本番必須localhost は http 可
Scope 設定明示的指定が必要デフォルトで十分
ユーザー情報email、name、picturelogin、email、avatar_url

注意点:GitHub のメールは null になる可能性があります(ユーザーがプライバシー保護設定している場合)。コードで判断が必要です:

const userEmail = session.user?.email || 'メール未提供'

WeChat(微信)ログイン設定(国内シーン)

WeChat ログインの3つの方式

これが一番混同しやすい点です。WeChat には3種類のログインがあり、利用シーンが全く異なります:

ログイン方式利用シーン要件ユーザー体験
開放平台-Webサイトアプリ独立したWebサイト企業資格、备案ドメイン、HTTPSスキャンログイン、PC対応
公衆号(公式アカウント)Webページ認証WeChat内H5ページ認証済み公衆号WeChatブラウザ内限定
企業微信(WeCom)企業内部システム企業微信アカウント社員限定

ここでは第一の「開放平台Webサイトアプリ」ログインを解説します。独立した Next.js サイト向けです。

WeChat 開放平台設定(ハードル高め)

前提条件

  • 企業の営業許可証(個人開発者は不可)
  • 备案(ICP登録)済みのドメイン
  • HTTPS 証明書

ステップ1:開発者アカウント登録

https://open.weixin.qq.com で「登録」、「网站应用开发者(Webサイトアプリ開発者)」を選択、営業許可証をアップロードし審査待ち(通常1-2営業日)。

ステップ2:Webサイトアプリ作成

審査通過後、管理センター → 网站应用 → 创建网站应用(Webサイトアプリ作成)で以下入力:

  • アプリ名
  • アプリ紹介
  • アプリ公式サイト:あなたのドメイン(备案必須)
  • 認可コールバックドメイン:ドメインのみ入力、プロトコルやパスは不要。例:yourdomain.com

注意:Google/GitHub と違い、WeChat はドメインのみ入力します。完全 URL ではありません。WeChat はそのドメイン下のパスを自動マッチングします。

提出後また審査(1-7日)。通過すると AppID と AppSecret が割り当てられます。

ステップ3:環境変数

WECHAT_APP_ID=你的AppID
WECHAT_APP_SECRET=你的AppSecret

NextAuth.js カスタム Provider

WeChat は内蔵されていないため、自作が必要です。幸い NextAuth.js にはカスタム Provider の仕組みがあります:

// app/api/auth/[...nextauth]/route.ts

const WeChatProvider = {
  id: "wechat",
  name: "WeChat",
  type: "oauth",
  authorization: {
    url: "https://open.weixin.qq.com/connect/qrconnect",
    params: {
      appid: process.env.WECHAT_APP_ID,
      scope: "snsapi_login",
      response_type: "code",
    },
  },
  token: {
    url: "https://api.weixin.qq.com/sns/oauth2/access_token",
    async request({ params, provider }) {
      const response = await fetch(
        `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${process.env.WECHAT_APP_ID}&secret=${process.env.WECHAT_APP_SECRET}&code=${params.code}&grant_type=authorization_code`
      )
      const tokens = await response.json()
      return { tokens }
    },
  },
  userinfo: {
    url: "https://api.weixin.qq.com/sns/userinfo",
    async request({ tokens }) {
      const response = await fetch(
        `https://api.weixin.qq.com/sns/userinfo?access_token=${tokens.access_token}&openid=${tokens.openid}`
      )
      return await response.json()
    },
  },
  profile(profile) {
    return {
      id: profile.unionid || profile.openid,
      name: profile.nickname,
      email: null, // WeChat はメールを提供しない
      image: profile.headimgurl,
    }
  },
}

export const authOptions = {
  providers: [
    WeChatProvider,
    // ...他のproviders
  ],
}

開発環境デバッグプラン

WeChat ログインの最大の難点はローカルデバッグです。HTTPS かつ备案済みドメインが必須だからです。私は通常この2つの方法を使います:

案1:内網穿透(イントラネット貫通・推奨)

ngrok や cpolar を使い、ローカル3000ポートを公網にマッピングします:

# ngrok 使用
ngrok http 3000

# cpolar 使用(国内ではより安定)
cpolar http 3000

https://abc123.ngrok.io のような一時ドメインが生成されるので、これを WeChat 開放平台の認可コールバックドメインに設定します。

案2:テストアカウント使用

WeChat はテスト用アカウントを提供しており、企業資格不要です:

ただしテストアカウントは自分専用で、他人がスキャンすると「未フォローの公式アカウント」というエラーになります。

WeChat ログインの独自仕様

違い1:openid と unionid の返却

  • openid:現在のアプリにおけるユーザーの唯一のID
  • unionid:同一開放プラットフォームアカウント下の全アプリにおけるユーザーの唯一のID(複数アプリを紐付けている場合のみ)

ユーザー識別に unionid を使うことを推奨します。なければ openid で。

違い2:メールアドレスなし

WeChat API はメールを返さないため、profile の email は null です。ユーザー体系がメール必須なら、ユーザーに追加情報を入力させる必要があります。

違い3:access_token 有効期限が短い

Google/GitHub の token は通常1時間ですが、WeChat は2時間です。また1日のリフレッシュ回数に制限があります(確か10回)。token リフレッシュロジックは慎重に扱う必要があります。

まとめ

OAuth の原理から3大プラットフォームの実戦設定まで、サードパーティログインの全フローを見てきました。

核心ポイントの振り返り

  • OAuth の code と token の2段階設計はセキュリティのため。code はブラウザで平文送信OKだが、secret はバックエンドに隠す必要がある。
  • NextAuth.js はビジネスロジックに集中させてくれる。Session 管理や CSRF 防御などの詳細に煩わされない。
  • Google 設定は最も厳格、redirect URI 完全一致が必要。GitHub は最も開発者に優しい。WeChat は敷居が高く国内必須。
  • WeChat ログインは企業資格と备案ドメインが必要。開発段階では内網穿透+テストアカウントでデバッグする。

実用テクニック

  • openssl rand -base64 32 で NEXTAUTH_SECRET を生成する(手書きしない)
  • Google Console には複数のポートの redirect URI を設定しておく(ポート変更時のエラー回避)
  • GitHub のメールは null の可能性があるので、空値処理を忘れない
  • WeChat の unionid は openid よりアプリ間連携に適している

正直、サードパーティログインで一番難しいのはコードを書くことではなく、OAuth の設計思想と各プラットフォームの設定差分を理解することです。この記事がいくつかの落とし穴を避ける助けになれば嬉しいです。

次に「Google ログイン追加して」と言われたら、もう午後の時間を潰さずに済むはずです。

Next.js OAuth ログイン完全設定フロー

OAuth 原理の理解から Google、GitHub、WeChat ログインの設定までの完全な手順

⏱️ Estimated time: 2 hr

  1. 1

    Step1: OAuth フローの理解(代理荷物受取の例え)

    OAuth の核心思想:パスワードをサードパーティアプリに渡さず、OAuth プロバイダーから一時的な通行証をもらう権限を与えるだけ。

    代理荷物受取の例え:
    • あなた(ユーザー)→ ログインしたい人
    • 友人(Next.js アプリ)→ 代わりに荷物を受け取る人
    • 配送センター(OAuth プロバイダー)→ Google、GitHub、WeChat
    • 門限カード(パスワード)→ 他人に渡してはいけない
    • 一時通行証(access_token)→ 有効期限と権限制限あり

    4ステップフロー:
    1. あなたが友人に受取コード(authorization code)を渡す
    2. 友人が受取コードと身分証を持って配送センターへ(code+client_secret で access_token と交換)
    3. 配送センターが本人確認をして荷物(ユーザー情報)を渡す
    4. 友人が荷物をあなたに渡す(ログイン成功)

    重要ポイント:
    • 受取コード(code)は一度きり、有効期限短い(通常10分)
    • 身分証(client_secret)は秘密、サーバーサイドでのみ使用
    • 一時通行証(access_token)には有効期限と権限制限がある
  2. 2

    Step2: Google ログインの設定

    1. Google Cloud Console で OAuth クライアント作成:
    • https://console.cloud.google.com にアクセス
    • プロジェクト作成 → API とサービス → 認証情報 → OAuth クライアント ID 作成
    • アプリタイプ:Web アプリケーション
    • 承認済みのリダイレクト URI:http://localhost:3000/api/auth/callback/google

    2. client_id と client_secret を取得

    3. NextAuth.js 設定:
    ```ts
    // app/api/auth/[...nextauth]/route.ts
    import NextAuth from 'next-auth'
    import GoogleProvider from 'next-auth/providers/google'

    export const authOptions = {
    providers: [
    GoogleProvider({
    clientId: process.env.GOOGLE_CLIENT_ID!,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
    })
    ],
    }
    ```

    4. 環境変数設定:
    ```
    GOOGLE_CLIENT_ID=your_client_id
    GOOGLE_CLIENT_SECRET=your_client_secret
    NEXTAUTH_URL=http://localhost:3000
    NEXTAUTH_SECRET=random_string
    ```

    5. ページで使用:
    ```tsx
    import { signIn } from 'next-auth/react'

    <button onClick={() => signIn('google')}>
    Google でログイン
    </button>
    ```
  3. 3

    Step3: GitHub ログインの設定

    1. GitHub で OAuth App 作成:
    • https://github.com/settings/developers にアクセス
    • New OAuth App
    • Authorization callback URL:http://localhost:3000/api/auth/callback/github

    2. Client ID と Client Secret を取得

    3. NextAuth.js 設定:
    ```ts
    import GitHubProvider from 'next-auth/providers/github'

    providers: [
    GitHubProvider({
    clientId: process.env.GITHUB_CLIENT_ID!,
    clientSecret: process.env.GITHUB_CLIENT_SECRET!,
    })
    ]
    ```

    4. 環境変数設定:
    ```
    GITHUB_CLIENT_ID=your_client_id
    GITHUB_CLIENT_SECRET=your_client_secret
    ```

    ポイント:GitHub の設定フローは Google に似ていますが、OAuth プロバイダーが異なるだけです
  4. 4

    Step4: WeChat ログインの設定(特殊処理)

    1. WeChat 開放平台でアプリ登録:
    • https://open.weixin.qq.com にアクセス
    • Web サイトアプリ作成
    • AppID と AppSecret 取得
    • 企業資格が必要

    2. 認可コールバックドメイン設定:
    • 形式:yourdomain.com(http://やhttps://を含まない)
    • ICP 备案済みのドメインが必要

    3. カスタム Provider 設定:
    ```ts
    import WeChatProvider from 'next-auth/providers/wechat'

    providers: [
    WeChatProvider({
    clientId: process.env.WECHAT_CLIENT_ID!,
    clientSecret: process.env.WECHAT_CLIENT_SECRET!,
    })
    ]
    ```

    4. ローカルデバッグは内網穿透を使用:
    • ngrok や frp を使用
    • コールバックアドレスを内網穿透アドレスに設定
    • テスト完了後に本番アドレスに変更

    ポイント:
    • WeChat ログインは企業資格が必要
    • ローカルデバッグには内網穿透が必要
    • unionid は openid よりユーザー識別に適している
  5. 5

    Step5: よくあるエラーの解決

    エラー1:redirect_uri_mismatch
    • 原因:コールバックアドレス不一致
    • 解決:OAuth プロバイダー管理画面で正しい redirect_uri を設定する
    • 注意:ローカルと本番の両方のコールバックアドレスを設定すること

    エラー2:環境変数未設定
    • 確認:.env.local ファイルが存在するか
    • 確認:環境変数名が正しいか
    • 確認:Vercel Dashboard で環境変数が設定されているか

    エラー3:ローカルは正常だが本番でエラー
    • 原因:本番とローカルのコールバックアドレスが異なる
    • 解決:OAuth プロバイダー管理画面で本番環境の redirect_uri を設定する
    • 形式:https://yourdomain.com/api/auth/callback/google

    安全への提案:
    • client_secret は必ず秘密にし、サーバーサイドでのみ使用する
    • state パラメータを使って CSRF 攻撃を防ぐ
    • コールバック URL の state パラメータを検証する

FAQ

OAuth フローとは一体何ですか?
代理荷物受取で理解する OAuth:

シーン:配送センターにあなたの荷物(ユーザー情報)がありますが、あなたは会社にいて自分で取りに行けません。友人(Next.js アプリ)に代わりに取りに行ってもらいます。

フロー:
1. あなたが友人に受取コード(authorization code)を渡す
• 「Google でログイン」をクリックすると、Google の認可ページへ飛びます
• 同意すると、Google は一時的な code を生成し、URL パラメータでアプリに渡します

2. 友人が受取コードを持って配送センターへ行く(code+client_secret で access_token と交換)
• アプリのバックエンドが code と client_secret を持って Google に access_token をもらいに行きます
• Google は友人が本当に信頼できる人か(client_secret)を確認します

3. 本人確認後に荷物を渡す(ユーザー情報)
• Google が code と client_secret を確認し、荷物(ユーザー情報)を友人に渡します
• 友人がそれをあなたに渡します(ログイン成功)

ポイント:
• 受取コード(code)は使い捨てで、有効期限が短い(通常10分)
• 身分証(client_secret)は秘密で、サーバーでのみ使用
• 一時通行証(access_token)には有効期限と権限制限がある

メリット:パスワードをサードパーティアプリに渡さず、OAuth プロバイダーから一時的な通行証をもらう権限を与えるだけで済みます。
redirect_uri_mismatch とは何ですか?
エラー原因:コールバックアドレスが一致していません。

OAuth プロバイダーはコールバックアドレスを検証します。設定したものと異なるとエラーになります。

解決方法:
1. OAuth プロバイダー管理画面で正しい redirect_uri を設定
2. ローカル開発:http://localhost:3000/api/auth/callback/google
3. 本番環境:https://yourdomain.com/api/auth/callback/google
4. 注意:ローカルと本番の両方を設定する必要があります

よくあるミス:
• ローカルしか設定していない
• コールバックアドレスの書き間違い(スラッシュの過不足)
• プロトコル間違い(http vs https)

確認方法:
• NextAuth.js のデフォルトコールバックパス:/api/auth/callback/[provider]
• OAuth プロバイダー管理画面の redirect_uri がこのパスと完全に一致しているか確認

注意:設定後、反映に数分かかることがあります。
WeChat ログインはなぜ厄介なのですか?
問題点:

1. 企業資格が必要
• 個人開発者は申請不可
• 営業許可証などの書類が必要
• 審査に1-3営業日かかる

2. ドキュメントが不親切
• 公式ドキュメントが分かりにくい
• エラーメッセージが不明確
• デバッグが困難

3. ローカルデバッグが面倒
• 内網穿透(ngrok や frp)が必要
• コールバックアドレス設定が複雑
• テスト環境の制限が多い

4. 設定が複雑
• カスタム Provider の設定が必要
• unionid と openid の違い
• 認可コールバックドメインの ICP 备案が必要

解決策:
• 内網穿透でデバッグ
• カスタム Provider を設定
• ユーザー識別には openid より unionid を使用
• 審査を気長に待つ

アドバイス:可能であれば Google や GitHub ログインを優先し、WeChat ログインは補助的に使いましょう。
カスタム Provider はどう設定しますか?
WeChat ログインにはカスタム Provider が必要です:

```ts
import type { OAuthConfig, OAuthUserConfig } from 'next-auth/providers'

function WeChatProvider(options: OAuthUserConfig<WeChatProfile>): OAuthConfig<WeChatProfile> {
return {
id: 'wechat',
name: 'WeChat',
type: 'oauth',
authorization: {
url: 'https://open.weixin.qq.com/connect/qrconnect',
params: {
appid: options.clientId,
redirect_uri: options.callbackUrl,
response_type: 'code',
scope: 'snsapi_login',
state: 'state',
},
},
token: {
url: 'https://api.weixin.qq.com/sns/oauth2/access_token',
},
userinfo: {
url: 'https://api.weixin.qq.com/sns/userinfo',
},
profile(profile) {
return {
id: profile.openid,
name: profile.nickname,
email: null,
image: profile.headimgurl,
}
},
...options,
}
}
```

ポイント:
• authorization URL の設定
• token URL の設定
• userinfo URL の設定
• profile 関数の実装

注意:WeChat ログインの設定は複雑なので、公式ドキュメントや既存の Provider を参考にすることをお勧めします。
unionid と openid の違いは何ですか?
openid:
• 現在のアプリにおけるユーザーの唯一の ID
• アプリごとに openid は異なる
• 単一アプリのシーンに適している

unionid:
• WeChat 開放プラットフォームにおけるユーザーの唯一の ID
• 同じユーザーなら異なるアプリでも unionid は同じ
• 複数アプリのシーンに適している

選択のアドバイス:
• 単一アプリ → openid
• 複数アプリ → unionid

コード例:
```ts
// unionid 取得
const response = await fetch(
`https://api.weixin.qq.com/sns/userinfo?access_token=${accessToken}&openid=${openid}`
)
const data = await response.json()
const unionid = data.unionid // ユーザー唯一の ID
```

ポイント:
• unionid は openid よりユーザー識別に適している
• unionid 取得にはユーザーの認可が必要
• unionid を使用するには WeChat 開放プラットフォームの設定が必要
ローカルで WeChat ログインをデバッグするには?
問題:WeChat ログインは認可コールバックドメインの設定が必要ですが、ローカルの localhost は設定できません。

解決策:内網穿透を使用

1. ngrok を使用:
```bash
ngrok http 3000
```

2. 公網アドレスを取得:
```
https://xxxxx.ngrok.io
```

3. コールバックアドレスを設定:
• WeChat 開放プラットフォームで設定:https://xxxxx.ngrok.io/api/auth/callback/wechat
• .env.local で設定:NEXTAUTH_URL=https://xxxxx.ngrok.io

4. テスト:
• https://xxxxx.ngrok.io にアクセス
• WeChat ログインをクリック
• フローをテスト

注意事項:
• ngrok 無料版のアドレスは変動するため、再起動ごとに更新が必要
• 本番環境では ngrok を使用しない
• テスト完了後に本番アドレスに変更する

アドバイス:frp などの自前内網穿透を使うと、アドレスが安定します。

10 min read · 公開日: 2025年12月19日 · 更新日: 2026年1月22日

コメント

GitHubアカウントでログインしてコメントできます

関連記事