Next.js+TSでNextAuth.jsを使ってcognito認証を行う
webアプリを作っていて、ログイン部分の実装のためにcognito認証を使ったので、その方法について書きます。
今回はAWS側で予め用意されているhosted UIを使う場合の記事となります。
Cognito側の設定
Amazon Cognito コンソールに移動して、ログイン後ユーザープールを作成します。
アプリクライアントの設定が必要になるので、設定しておきます。
ユーザープールが作成できたらアプリの統合 > アプリクライアントの設定からログイン時のコールバックURLに http://localhost:3000/api/auth/callback/cognito と入力します。
あとは必要なOAuthスコープを選択して、適当なドメイン名を追加すれば設定完了です。
NextAuth.jsのインストール
まずNextAuth.js[1]をインストールします。
yarn add next-auth
必要な環境変数の確認
https://next-auth.js.org/providers/cognito を読んで必要なenvの値をセット&&型補完がきくようにglobals.d.tsを追加します。(この手順は好みなのでなくても良いです)
declare namespace NodeJS {
// 環境変数名の定義
interface ProcessEnv {
readonly COGNITO_CLIENT_ID: string;
readonly COGNITO_CLIENT_SECRET: string;
readonly COGNITO_ISSUER: string;
}
}
COGNITO_CLIENT_ID、COGNITO_CLIENT_SECRET、COGNITO_ISSUERに関してはそれぞれawsコンソールから確認して、.env.local
に追加しておきます。
APIルートを追加
上記でコールバックURLに指定したhttp://localhost:3000/api/auth/callback/cognito に当たるルートの処理を書きます。
api
フォルダ配下にauth
を作成し、[...nextauth].ts
という名前のファイルを作成します。
import NextAuth from 'next-auth';
import CognitoProvider from 'next-auth/providers/cognito';
export default NextAuth({
providers: [
CognitoProvider({
clientId: process.env.COGNITO_CLIENT_ID,
clientSecret: process.env.COGNITO_CLIENT_SECRET,
issuer: process.env.COGNITO_ISSUER,
}),
],
});
これでhttp://localhost:3000/api/auth/callback/cognito にアクセスされた場合、上記の処理が走り、cognito認証ができるようになります。
クライアント側からcognitoログインできるようにする
最後に、クライアント側からcognito認証するための動線を追加します。
まずはSessionProvider
でコンポーネントをラップします。
import { SessionProvider } from 'next-auth/react';
import type { AppProps } from 'next/app';
import '../styles/globals.css';
function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) {
return (
<SessionProvider session={session}>
<Component {...pageProps} />
</SessionProvider>
);
}
export default MyApp;
これでNextAuth.js
側で用意されているhooks類などが呼び出せるようになります。
接続できることを確認するために、https://next-auth.js.org/getting-started/example#frontend---add-react-hook にかかれてあるとおりの処理をindex.tsx
に追加します。
import type { NextPage } from 'next';
import { signIn, signOut, useSession } from 'next-auth/react';
const Home: NextPage = () => {
const { data: session } = useSession();
if (session && session.user) {
return (
<>
Signed in as {session.user.email} <br />
<button onClick={() => signOut()}>Sign out</button>
</>
);
}
return (
<>
Not signed in <br />
<button onClick={() => signIn()}>Sign in</button>
</>
);
};
export default Home;
起動するとSignin
というボタンが見えます。
クリックすると以下の画面になります。※この画面はカスタム可能です(後述)
これを更にクリックするとhosted UIが現れます。
カスタマイズ
[...nextauth].ts
内にpagesを追加し、サインインページなどを別途指定することもできます。
import NextAuth from 'next-auth';
import CognitoProvider from 'next-auth/providers/cognito';
export default NextAuth({
providers: [
CognitoProvider({
clientId: process.env.COGNITO_CLIENT_ID,
clientSecret: process.env.COGNITO_CLIENT_SECRET,
issuer: process.env.COGNITO_ISSUER,
}),
],
+ pages: {
+ signIn: '/auth/signin',
+ signOut: '/auth/signout',
+ error: '/auth/error', // Error code passed in query string as ?error=
+ verifyRequest: '/auth/verify-request', // (used for check email message)
+ newUser: '/auth/new-user' // New users will be directed here on first sign in (leave the property out if not of interest)
+ }
});
この上で、例えば/auth/signin
ページを作成します。
import { GetServerSideProps, NextPage } from 'next';
import { OAuthProviderType } from 'next-auth/providers';
import {
ClientSafeProvider,
getProviders,
LiteralUnion,
signIn,
} from 'next-auth/react';
type Props = {
providers: Record<
LiteralUnion<OAuthProviderType, string>,
ClientSafeProvider
>;
};
const SignIn: NextPage<Props> = ({ providers }) => {
return (
<>
{Object.values(providers).map((provider) => (
<div key={provider.name}>
<button onClick={() => signIn(provider.id)}>
Sign in with {provider.name}
</button>
</div>
))}
</>
);
};
export const getServerSideProps: GetServerSideProps = async (context) => {
const providers = await getProviders();
return {
props: { providers },
};
};
export default SignIn;
再び起動してSignin
ボタンをクリックすると上記の画面が表示されます。
ただし、hosted UIに関してはcssで多少のカスタムはできるもののフルカスタマイズとなるとやはり最初に書いたとおりSDKを使わないと厳しいので、あくまでhosted UIにうつるまでの動線部分のカスタムとなります。
デプロイする際に行うこと
デプロイする際に、https://next-auth.js.org/getting-started/example#deploying-to-production に記述がある通り、NEXTAUTH_URL
という環境変数が必要となるので、追加してからデプロイする必要があります。
また、デプロイしたら、コールバックURLをhttp://localhost:3000 からアプリのURLに変更することも忘れないようにします。
以上です。
参考
-
ちなみに、今回
NextAuth.js
を使った理由は今後認証方法がcognito以外になったとしても書き換えが少ないかなと思ったからです。amplify
を使うほうが慣れているのですが、他の認証方法を知らないと思い挑戦してみました。 ↩︎
Discussion