Next.js - Auth.jsでGoogleカレンダーAPIを使う方法
Next.js
のAuth.js
を使用して、GoogleのカレンダーAPIにアクセスする方法です。App Router
を使用しています。
Auth.js
自体の説明はこちらをご覧ください。ここでは説明しません。
仕組み
技術的に言えば、OAuth 2.0になります。Googleから一時的なアクセストークンを払い出してもらい、それを使ってGoogleのAPIを叩きます。巷のサービスを使うとよくお目にかかりますが、Webブラウザで同意画面を提示し、ユーザに承諾ボタンを押してもらいます。承諾されると302リダイレクトで認可コード(authorization code)がGETパラメータで渡されます。最後にその認可コードを使用して、アクセストークンを払い出すGoogle APIを叩きます。
この仕組みはnext-authライブラリを使用するといい感じにやってくれるので、自分でコーディングする必要はありません。
手順
おおまかに言って、次の2ステップになります。
- GCPコンソール画面での設定
- Next.jsでのコーディング
GCPプロジェクトでの作業
GCPのWebコンソールのAPIs & Services画面から次の2つを設定します。私のブログではコンセプト的なことにフォーカスします。細かな操作手順は他の人のブログを見てください。
ここでは次のCredentials
とOAuth consent screen
を設定します。
Credentials
Client ID
とSecret Key
の払い出しをします。ここで重要なのはredirect URIを設定することです。Google側の画面でユーザがログインに成功すると302リダイレクト
をブラウザに返します。
http://localhost:3000/api/auth/callback/google
Next.js側の設定です。環境変数にClient ID
とSecret Key
を設定します。
GOOGLE_CLIENT_ID=96032...4tbslf.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=GOC...J_3SN
OAuth consent screen 同意画面
こちらの同意画面の設定をします。
ここでGoogleカレンダーAPIを(あなたのNext.jsサービスが)使いたいので許可をくださいとユーザにお願いしています。
ユーザがcontinue
ボタンを押すと、GoogleカレンダーAPIにアクセスするためのトークンを払い出すための認可コードをグーグルから払い出してもらえます。この認可コードは302リダイレクトを経由してnext-authのAPI(先ほど設定したredirect URI)に渡されます。この認可コードを使用して、Googleのアクセストークンを払い出すAPIを叩くとめでたくアクセストークンがゲットできます。このあたりの処理がnext-auth
に実装されています。
GCPコンソールのscope
の設定のところで許可をもらうロールを選択します。ここではGoogleカレンダーのリードオンリー権限に対してユーザに同意もらう設定をします。どんなスコープがあるかの一覧はこちらで確認できます。
Next.js側の作業です。このスコープをnext-auth
のoptions.ts
のscope
で指定する必要があります。
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
authorization: {
params: {
prompt: "consent",
access_type: "offline",
response_type: "code",
scope: "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/calendar.readonly",
}
}
}),
optionsのcallbacksの設定です。Googleから払い出してもらったトークンをバケツリレー(jwt->session)でセットします。セキュリティの観点からデフォでは闇雲にコピーしないようになってます。
callbacks: {
jwt: async ({token, user, account, profile, isNewUser}) => {
if (user) {
token.user = user;
const u = user as any
token.role = u.role;
}
if (account) {
token.accessToken = account.access_token
token.refreshToken = account.refresh_token
}
return token;
},
session: ({session, token}) => {
token.accessToken
return {
...session,
user: {
...session.user,
role: token.role,
accessToken: token.accessToken,
refreshToken: token.refreshToken,
},
};
},
}
サーバ・コンポーネントに実装
さて、いよいよ準備が整ったところでNext.jsのコーディングをしましょう。
GoogleのカレンダーAPIを呼び出すためには、Google提供のSDKを使用します。
例えば、カレンダー一覧を取得するには、await calendar.calendarList.list()
のように呼び出します。非同期対応しています。公式サンプルもあります。
Node.jsのライブラリをインストールします。
npm install googleapis
getServerSession(options)
を呼び出すと、先ほど設定したcallback.session
の戻り値を受け取ります。user.accessToken
にGoogleのトークンを仕込んだことを思い出してください。
あとは、コード内のコメントを参考にしてください。ソースコードはこちらにあります。
import {getServerSession} from "next-auth/next";
import {options} from "@/app/options";
import {google, calendar_v3} from 'googleapis'
import Calendar = calendar_v3.Calendar
export default async function Page() {
// サーバ・コンポーネントでセッションを取得する。
const session = await getServerSession(options)
const user = session?.user
// Google OAuthへの接続
const oauth2Client = new google.auth.OAuth2({
clientId: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
// GCPコンソールで設定したredirect URI
redirectUri: 'http://localhost:3000/google-calendar'
})
const accessToken = user?.accessToken // Googleが払い出したアクセストークン
if (!accessToken) {
return (
<div>accessToken is null</div>
)
}
// トークンを設定。refresh_tokenも渡せます。
oauth2Client.setCredentials({access_token: accessToken})
// カレンダーオブジェクト作成
const calendar: Calendar = google.calendar({version: 'v3', auth: oauth2Client})
// カレンダー一覧を取得
const calendarResponse = await calendar.calendarList.list()
console.log(calendarResponse.data)
return (
<main
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "70vh",
}}
>
<div>
<div>よしなにレンダリング。calendarResponse.data</div>
</div>
</main>
);
}
Chrome Dev Tool
yarn dev
で実行し、Chrome Dev Toolでネットワークを見てみましょう。
下の図は最初にGoogleからのログイン画面を表示させているところです。
Client ID、scope、redirect_uri
を飛ばしているのがわかりますね。
次は、ユーザが同意画面でOKしたときのコールバックです。ここで302でリダイレクトさせていることに注目してください。GCPコンソールで設定したredirect_uri
をキックさせます。その際に承認コードをGETパラメータで飛ばしています。next-auth側でこのGETパラメータを受け取り、Googleのアクセストークンを払い出すAPIを叩く(Next.js側から)わけです。
Vercelへのデプロイ
先ほどの、Credentials
のredirect URI
を変更するか、新規にClient ID
を作成します。新規に作った方が良いでしょう。
参考
Discussion