Next.jsでGoogleAPIのOAuth2.0認可を実装する
はじめに
Next.jsでGoogleAPIのOAuth2.0認可を実装したので記事を投稿します。OAuth2.0の認可コードフローを使ってアクセストークン及びリフレッシュトークンを取得しています。
本記事ではトークンの取得までを行い、トークンを使ったGoogleAPIの呼び出しは別の記事として投稿したいと考えています。
参考資料
本記事に関連するGoogleのドキュメントは以下です。以下のドキュメントのNode.jsのコードサンプルを元に、Next.jsで実装を行いました。
1. GoogleCloudでクライアントアプリを設定する
1.1. GoogleCloudで新しいプロジェクトを作成する
まずはGoogleCloudで新しいプロジェクトを作成します。ここではwaitedという名前でプロジェクトを作成しています。
1.2. 有効なAPIとサービスを指定する
GoogleCloudのAPIとサービス > 有効なAPIとサービスから、認可を取得して利用したいAPI及びサービスを有効にします。ここではGmailAPIを有効にしています。
1.3. OAuth同意画面を作成する
GoogleCloudのAPIとサービス > OAuth同意画面からOAuth同意画面の作成を行います。アプリを公開する範囲に合わせてUserTypeを選択してください。筆者はUserTypeを「外部」としました。
1.3.1. OAuth同意画面に表示するアプリ情報を入力する
必須項目のアプリ名や任意項目のアプリのロゴなど、ユーザーがOAuthの同意を行う際に、アプリを認識するための情報を入力します。
1.3.2. スコープを指定する
OAuth同意画面でユーザーに認可を求める権限をスコープとして指定します。ここではユーザー本人に代わってGmailを送信するためのスコープであるhttps://www.googleapis.com/auth/gmail.send
を指定しています。
1.2. 有効なAPIとサービスを指定するの手順でGmailAPIを有効にしたことで、GmailAPIのために必要なスコープが選択できるようになっています。
1.3.3. テストユーザーを指定する
テストユーザーにテストに使用するGoogleアカウントを指定します。
1.3.4. 概要を確認する
最後に概要で設定内容を確認して、問題が無ければ「ダッシュボードに戻る」をクリックします。これでOAuth同意画面の作成は完了です。
1.4. OAuthクライアントIDを作成する
GoogleCloudのAPIとサービス > 認証情報から認証情報を作成します。OAuthクライアントIDを選択します。
今回はNext.jsでウェブアプリケーションとして実装するため、アプリケーションの種類はウェブアプリケーションを指定します。
承認済みのJavaScript生成元は、Next.jsをローカル起動させるhttp://localhost:3000
を指定し、承認済みのリダイレクトURLはhttp://localhost:3000/api/oauth2callback
としています。後ほどリダイレクトURLに指定した/api/oauth2callback
をNext.jsでAPIとして実装します。
これで、クライアントアプリが作成されました。GoogleCloudのAPIとサービス > 認証情報からクライアントIDとクライアントシークレットを取得することができます。これらの値はOAuth2.0認可の実装で必要になります。
2. Next.jsでOAuth2.0認可を実装する
ここからはNext.jsでOAuth2.0認可を実装していきます。参考に今回実装するOAuth2.0認可の処理の流れをシーケンス図として載せておきます。この段階でシーケンス図を見て処理のイメージが湧かない方でも、実装と動作確認後に再びシーケンス図を眺めてみると、イメージが湧いてくるのではないかと思います。
2.1. Next.JSアプリを新規作成する
まずは、以下のコマンドを実行してNext.jsアプリを新規作成します。
npx create-next-app@latest
コマンドを実行するとプロジェクト名や使用するライブラリなどを尋ねられます。プロンプトに従って入力を行ってください。例として、筆者はプロジェクト名をwaited、その他の選択肢は全てデフォルト値で以下の通り選択しています。筆者はTailwindCSSが好きです。
√ What is your project named? ... waited
√ Would you like to use TypeScript? ... Yes
√ Would you like to use ESLint? ... Yes
√ Would you like to use Tailwind CSS? ... Yes
√ Would you like to use `src/` directory? ... No
√ Would you like to use App Router? (recommended) ... Yes
√ Would you like to customize the default import alias (@/*)? ... No
以下のコマンドを実行することで、ローカル開発サーバーを起動することができます。
npm run dev
ブラウザを開き、http://localhost:3000 を指定すると、ローカル開発サーバにアクセスすることができます。
2.2. GoogleAPIクライアントライブラリをインストールする
次に、以下のコマンドを実行してGoogleAPIクライアントライブラリをインストールします。GoogleAPIクライアントライブラリは様々な開発言語に対してリリースされています。ここでは、GoogleAPI Node.jsクライアントをインストールしています。
npm install googleapis
GoogleAPIに対して直接HTTPリクエストを行うこともできますが、セキュリティの観点からGoogleAPIクライアントライブラリを使うことが強くお勧めされています。
2.3. OAuth2.0アクセストークンの取得を実装する
Next.jsのRouteHandlersの仕組みを使って、2つのAPIを実装します。oauth2Client
の生成には1.4. OAuthクライアントIDを作成するで取得したクライアントIDとクライアントシークレットを指定してください。
2.3.1. Googleの認可サーバーへリダイレクトするためのAPIを実装する
まずは自身のアプリからGoogleの認可サーバーへリダイレクトするためのAPIを実装します。ここでは、GoogleAPIクライアントライブラリを使って、Googleの認可サーバーのURLを取得して、取得したURLに対してリダイレクトを行っています。
これらの処理をAPIとして実装して、バックエンドで処理を行うことで、クライアントIDとクライアントシークレットを安全に保存することができます。
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const scopes = ['https://www.googleapis.com/auth/gmail.send'];
const {google} = require('googleapis');
const oauth2Client = new google.auth.OAuth2(
"クライアントID",
"クライアントシークレット",
"http://localhost:3000/api/oauth2callback"
);
const authorizationUrl = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes,
include_granted_scopes: true
});
return NextResponse.redirect(new URL(authorizationUrl, request.url));
}
authorizationUrl
がアプリからリダイレクトするGoogleの認可サーバーのURLです。
http://localhost:3000/api/oauth2callback
がGoogle認可サーバーでの認可後にリダイレクトされるアプリのURLです。1.4. OAuthクライアントIDを作成するで指定したリダイレクトURLと一致させる必要があります。
2.3.2. Googleの認可サーバーからリダイレクトを受けるためのAPIを実装する
次に、Googleの認可サーバーからリダイレクトを受けるためのAPIを実装します。ここでは、GoogleAPIクライアントライブラリを使って、リダイレクト時にクエリパラメータとして付加された認証コードからアクセストークン及びリフレッシュトークンを取得しています。
import { NextRequest, NextResponse } from "next/server";
export async function GET(request: NextRequest) {
const {google} = require('googleapis');
const oauth2Client = new google.auth.OAuth2(
"クライアントID",
"クライアントシークレット",
"http://localhost:3000/api/oauth2callback"
);
const url = require('url');
const q = url.parse(request.url, true).query;
if (q.error) {
console.log('Error:' + q.error);
return NextResponse.redirect(new URL("/", request.url));
}
const { tokens } = await oauth2Client.getToken(q.code);
oauth2Client.setCredentials(tokens);
let userCredential: { access_token: string; refresh_token: string;} = { access_token: "", refresh_token: ""};
userCredential = tokens;
console.log(`access_token: ${userCredential.access_token}`);
console.log(`refresh_token: ${userCredential.refresh_token}`);
return NextResponse.redirect(new URL("/", request.url));
}
本来は、ここで取得したアクセストークンを使ったGoogleAPIの呼び出しや、リフレッシュトークンのDBへの保存を行います。こちらの実装ではアクセストークンとリフレッシュトークンをコンソールログに出力して、アプリのトップページである/
にリダイレクトしています。
2.4. OAuth2.0認可を取得するトリガとなるボタンを実装する
最後に、OAuth2.0認可を取得するトリガとなるボタンを実装します。Next.jsアプリを新規作成した際に取得されたapp/page.tsの実装を以下の実装に置き換えます。ここではGoogleの認可サーバーへリダイレクトするためのAPIである/api/oauth2
へのリンクを「OAuth2.0」ボタンとして中央に表示するUIを実装しています。
import Link from "next/link";
export default function Home() {
return (
<main className="flex min-h-screen flex-col items-center justify-center p-24">
<Link href="/api/oauth2" className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
OAuth2.0
</Link>
</main>
);
}
3. ローカル開発サーバーを起動して動作を確認する
ローカル開発サーバーを起動して、動作を確認していきましょう。
3.1. ローカル開発サーバーを起動する
以下のコマンドを実行することで、ローカル開発サーバーを起動します。
npm run dev
ブラウザを開き、http://localhost:3000 を指定すると、ローカル開発サーバにアクセスし、「OAuth2.0」ボタンが表示されます。
3.2. Googleログインして認可を行う
「OAuth2.0」ボタンをクリックすると、Googleの認可サーバーにリダイレクトされます。
1.3.3. テストユーザーを指定するで指定したテストユーザーでGoogleにログインすることで、認可を行うことができます。
3.3. バックエンドのコンソールログにアクセストークンが出力される
認可が完了すると、Google認可サーバーからアプリのトップページへリダイレクトされ、再び「OAuth2.0」ボタンが表示されます。
この時、npm run dev
を実行したコンソールにコンソールログとしてアクセストークンとリフレッシュトークンの値が表示されれば正しく動作しています。
アクセストークンの取得処理はバックエンドで処理を行っているため、フロントエンドであるブラウザのコンソールログには結果が出力されないことに注意してください。
おわりに
記事を読んでいただいてありがとうございました。今回はNext.jsでGoogleAPIのOAuth2.0認可を実装しました。OAuth2.0実装の具体例として、どなたかの参考になれば嬉しいです。
この記事ではアクセストークンの取得までを紹介しました。また、アクセストークンを使ったGoogleAPIの呼び出しも別の記事として投稿していきたいと思います。
Discussion