📘

NextAuth.jsを使ってDrupalのOAuthを利用する

に公開

概要

NextAuth.jsを使ってDrupalのOAuthを利用する方法に関する備忘録です。

挙動

Next.jsで作成したアプリにアクセスして、「Sign in」ボタンを押します。

Drupalにログインしていない場合には、ログイン画面に遷移します。

ログイン済みの場合、「許可」するかのボタンが表示されるので、許可します。

ログイン情報が表示されます。

Drupal側の準備

モジュールのインストール

以下のモジュールをインストールします。

https://www.drupal.org/project/simple_oauth

本記事執筆時点の最新の以下をインストールしました。

composer require 'drupal/simple_oauth:^6.0@beta'

トークンを暗号化するための鍵の生成

鍵のペアを生成し、セキュリティのためにドキュメントルートの外に保存します。

openssl genrsa -out private.key 2048
openssl rsa -in private.key -pubout > public.key

鍵のパスを設定

鍵のパスを管理画面で設定します:

/admin/config/people/simple_oauth

Amazon LightsailでDrupalを動作させている場合、以下のように、ユーザを変更する必要がありました。

sudo chown daemon:daemon private.key

Clients

/admin/config/services/consumerにアクセスします。

default_consumerがすでに作成されているため、こちらを編集します。

Postmanでの動作確認

以下のように入力します。Drupalがhttps://drupal.example.orgにセットアップされていると過程します。

「新しいアクセストークンを取得」を押すと、冒頭の挙動で示した通り、Drupalの画面に遷移し、許可したのち、以下に遷移しました。

https://oauth.pstmn.io/v1/callback?code=...

Next.jsからの利用

ソースコードを以下でご確認いただけます。

https://github.com/nakamura196/drupal_oauth_app

完全の余地があるかと思いますが、以下のような設定により、動作確認ができました。

/src/app/api/auth/[...nextauth]/authOptions.js
export const authOptions = {
  // debug: true, // next-auth のデバッグモードを有効化
  providers: [
    {
      id: "drupal",
      name: "Drupal",
      type: "oauth",
      clientId: process.env.DRUPAL_CLIENT_ID,
      clientSecret: process.env.DRUPAL_CLIENT_SECRET,
      authorization: {
        url: process.env.DRUPAL_AUTH_URL,
        params: {
          scope: process.env.DRUPAL_SCOPE,
          response_type: "code",
          redirect_uri: `${process.env.NEXTAUTH_URL}/api/auth/callback/drupal`, // 環境変数からリダイレクトURIを構築
        },
      },
      token: {
        async request(context) {
          const body = new URLSearchParams({
            client_id: process.env.DRUPAL_CLIENT_ID, // 明示的に client_id を追加
            client_secret: process.env.DRUPAL_CLIENT_SECRET,
            code: context.params.code, // 認可コード
            grant_type: "authorization_code",
            redirect_uri: `${process.env.NEXTAUTH_URL}/api/auth/callback/drupal`,
          });

          const res = await fetch(process.env.DRUPAL_TOKEN_URL, {
            method: "POST",
            headers: {
              "Content-Type": "application/x-www-form-urlencoded",
            },
            body,
          });

          const json = await res.json(); // Parse the response body once

          if (!res.ok) {
            throw new Error(`Token request failed: ${res.statusText}`);
          }

          return {
            tokens: json
          }
        }
      },
      profile(profile) {
        return {
          id: profile.sub, // "sub" をユーザーの一意のIDとして利用
          name: profile.name || profile.preferred_username || "Unknown User", // 名前の優先順位を設定
          email: profile.email || "No Email Provided", // メールがない場合のフォールバック
          image: profile.profile || null, // プロファイルURLを画像として使用(必要に応じて調整)
        }
      },
    },
  ],
  callbacks: {
    async session({ session, token }) {
      // トークンからセッションに必要な情報を追加
      session.accessToken = token.accessToken;
      session.user.id = token.id;
      return session;
    },

    async jwt({ token, account, user }) {
      if (account) {
        token.accessToken = account.access_token;
      }
      if (user) {
        token.id = user.id; // プロファイルからユーザーIDをトークンに保存
      }
      return token;
    },
  },
};

まとめ

DrupalのOAuthの利用にあたり、参考になりましたら幸いです。

Discussion