NextAuth.js と AWS Cognito を利用してユーザー認証をする
https://gyazo.com/38bc81f2d216a85cbf09057e41a85b19
Cognito プロバイダーの作成
アプリケーションの統合 > アプリクライアントと分析から、クライアントを作成する。
また、ドメインを設定する。サインイン URL を時のドメインのようなので、使用可能であれば任意の文字列を設定できる。
また、自分で取得したドメインを設定することもできる。
コールバック URL は http://localhost:3000/api/auth/callback/cognito にする。
クライアント ID / シークレットは画面から取得できる。
イシュアーは、下記のように組み立てた値を利用する。
code:text
その後、 .env.local を以下のように作成する。
code:.env.local
COGNITO_CLIENT_ID=XXXXXXXXXXXXXXXXXXXXXXX
COGNITO_CLIENT_SECRET=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
NEXTAUTH_SECRET=secret-string
NEXTAUTH_SECRET はローカル環境では適当な文字列で良さそう。
NextAuth の設定
一般的な設定をまずはする。
ここで少し修正した点がある。
Next.js 14 あたりで、 route.ts から export できる関数名に制限がかかったようで、 GET や POST しかできないようだ。
( npm run dev しているうちは問題ないが、 build するとエラーになる。)
そのため、 authOptions は別ファイルに作成する。
その上で、 CognitoProvider の設定をする。
export const authOptions: NextAuthOptions = {
providers: [
CognitoProvider({
clientId: process.env.COGNITO_CLIENT_ID ?? '',
clientSecret: process.env.COGNITO_CLIENT_SECRET ?? '',
issuer: process.env.COGNITO_ISSUER,
}),
],
};
import NextAuth from 'next-auth';
import authOptions from "./authOptions";
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST };
idToken などを取得する
デフォルトだと、 name、 email、 image が取得できる。
ただ、API Gateway の認証として Cognito を利用している場合などに Cognito から払い出されるトークン類が必要かと思われる。
その場合は、 NextAuth の型定義を拡張した上で、トークン、セッションに値を付与していく。
なお、トークン系は account 引数に、ユーザー情報は profile 引数に格納されている。
code:next-auth.d.ts
import { JWT as NextAuthJWT } from 'next-auth/jwt';
import { DefaultSession, DefaultUser, Profile as DefaultProfile } from 'next-auth';
declare module 'next-auth' {
interface Session {
accessToken?: string;
error?: string;
user: {
id?: string;
idToken?: string;
accessToken?: string;
accessTokenExpires?: number;
refreshToken?: string;
groups?: string[];
familyName?: string;
firstName?: string;
}
interface Profile extends DefaultProfile {
'cognito:groups'?: string[];
family_name?: string;
first_name?: string;
}
}
declare module 'next-auth/jwt' {
interface JWT extends NextAuthJWT {
id?: string;
idToken?: string;
accessToken?: string;
accessTokenExpires?: number;
refreshToken?: string;
groups?: string[];
familyName?: string;
firstName?: string;
}
}
export const authOptions: NextAuthOptions = {
// ...
callbacks: {
async jwt({ token, user, account, profile }) {
if (account) {
token.id = user.id;
token.idToken = account.id_token;
token.accessToken = account.access_token;
token.accessTokenExpires = account.expires_at;
token.refreshToken = account.refresh_token;
}
if (profile) {
token.groups = profile.groups;
token.familyName = profile.family_name;
token.firstName = profile.first_name;
}
return token;
},
async session({ session, token }) {
if (token?.idToken) {
session.user.id = token.id;
session.user.idToken = token.idToken;
session.user.accessToken = token.accessToken;
session.user.accessTokenExpires = token.accessTokenExpires;
session.user.refreshToken = token.refreshToken;
session.user.groups = token.groups;
session.user.familyName = token.familyName;
session.user.firstName = token.firstName;
}
return session;
}
},
};
トークンなどの情報は authorize メソッドの引数に account として渡される。
この値をトークンやセッションにセットする。(必要な情報に限った方が良い)
後は他のプロバイダーを仕様する場合と同様、 signIn メソッドから遷移することで Cognito のログインページに遷移できる。
認証が済めば、指定のページにリダイレクトされる。
UI のカスタマイズ
Cognito の OAuth プロバイダーを仕様する場合、ログイン画面の CSS はカスタマイズはできるものの、日本語にしたりそもそもを変更することはできないよう。