Auth0 は認証・認可サービスをクラウドで提供している SaaS ベンダーです。
「認証」という機能はどのアプリケーションにも求められる重要な要件ですが、プロダクトの本質的なビジネス価値を持たない場合が多いでしょう。Auth0 を使用することで、この「認証」機能という Undifferentiated Heavy Lifting な作業を排除できます。
本記事では、簡単な React アプリケーションを作成して Auth0 を使用した認証機能を実装します。また、作成したアプリケーションを Vercel(旧 Zeit now)にデプロイする方法を解説します。ユーザのサインアップ後の確認メールなどは SendGrid から送信されます。
以下は、本記事で紹介するアプリケーションの簡単な構成図です。また、本記事で実装されたアプリケーションは Vercel にデプロイしています。こちらからアクセスできます。ソースコードは以下の GitHub リポジトリにホストしています。
React アプリケーションの雛形を作る
まずは create-react-app
を使用して簡単なアプリケーションを実装していきます。
$ create-react-app app --typescript
react-router
$ yarn add react-router react-router-dom
$ yarn add -D @types/react-router @types/react-router-dom
最初の react-router はシームレスなナビゲーションを可能にするメインのライブラリです。ふたつめは react-router-dom で、React ルーターの DOM 結合を提供します。-D
オプションをつけることで開発時にのみ使用するライブラリをインストールできます。この例では TypeScript の型定義ライブラリをインストールしています。
react-bootstrap
最低限のデザインを整えるために react-bootstrap
を使用します。
$ yarn add react-bootstrap react-bootstrap-icons bootstrap
$ yarn add -D @types/react-bootstrap
auth0-react
Auth0 の SDK である auth0-react
をインストールします。後述しますが、従来の auth0-spa-js
などに比べると Hooks 化の対応が進んでおり、本当に最小限のコードで認証機能を実装できます。
$ yarn add @auth0/auth0-react
auth0-react を使用して認証機能を実装する
auth0-react の公式ドキュメント でも解説していますが、本記事ではもう少し実際の開発のユースケースを想定してガイドします。
Auth0Provider
まずは index.tsx
にて <App/>
コンポーネントを <Auth0Provider/>
でラップします。このようにしておくことで、 <App/>
コンポーネント内で useAuth0
フックを使用できるようになります。 useAuth0
フックを使用することで、以下のような様々な認証に関するステートおよびメソッドを取得することができます。
- ステートの例: isLoading, isAuthenticated, user
- メソッドの例: loginWithRedirect, logout
import React from "react";
import ReactDOM from "react-dom";
import { Auth0Provider } from "@auth0/auth0-react";
import "bootstrap/dist/css/bootstrap.min.css";
import { App } from "./App";
ReactDOM.render(
<Auth0Provider
domain={process.env.REACT_APP_AUTH0_DOMAIN!}
clientId={process.env.REACT_APP_AUTH0_CLIENT_ID!}
redirectUri={window.location.origin}
>
<App />
</Auth0Provider>,
document.querySelector("#root")
);
domain および、clientId には Auth0 のマネジメントコンソール画面で作成した Application の domain, clientId を入力してください。
LoginButton
ログインボタンは useAuth0
フックを使用すると簡単に実装できます。loginWithRedirect
メソッドを実行すると Auth0 の SSO エンドポイントを使用してログインした後に、自身のアプリケーションにリダイレクトします。
import React from "react";
import { useAuth0 } from "@auth0/auth0-react";
import { Button } from "react-bootstrap";
function LoginButton() {
const { isAuthenticated, loginWithRedirect } = useAuth0();
return !isAuthenticated ? (
<Button onClick={loginWithRedirect}>Log in</Button>
) : null;
}
export default LoginButton;
実際にログインボタンを押した振る舞いは以下のようになります。
ログイン処理の際、Auth0 のエンドポイントにアクセスし、自身のアプリケーションにリダイレクトします。事前に Application URIs の各種設定をしておきましょう。以下の例では開発用に localhost:3000
、 本番デプロイ用として https://auth0-todo-app.vercel.app/
を設定しています。
LogoutButton
ログアウト処理には logout
メソッドが用意されています。
ログアウト後に表示するパスを returnTo: xxxx
で指定します。
import React from "react";
import { useAuth0 } from "@auth0/auth0-react";
import { Button } from "react-bootstrap";
function LogoutButton(props: any) {
const { isAuthenticated, logout } = useAuth0();
return isAuthenticated ? (
<Button
variant="outline-primary"
onClick={() => {
logout({ returnTo: window.location.origin });
}}
{...props}
>
Log out
</Button>
) : null;
}
export default LogoutButton;
UserProfile
ログインユーザの情報は user
を使用して取得します。認証プロバイダー(Google, Facebook, etc...)によって取得できる情報は異なります。以下では、ログインユーザのアバター画像を user.picture
として取得しています。
import React from "react";
import { useAuth0 } from "@auth0/auth0-react";
import { Image } from "react-bootstrap";
export const UserProfileAvatar = (props: any) => {
const { user } = useAuth0();
return (
<Image
style={{ width: "30px" }}
src={user.picture}
roundedCircle
{...props}
/>
);
};
この記事のサンプルアプリケーションでは、この情報を組み合わせて、ユーザアイコンをクリックすると各種メニューが表示されるようにしています。
認証済みのユーザだけ見れるページを制御する
react-router-dom を使用した実装ではおなじみの PrivateRoute を組み込んでいきます。
auth0-react
では、ログインしていないユーザが表示しようとすると、ログインページにリダイレクトする withAuthenticationRequired()
が用意されています。
以下のように ProtectedRoute
のようなルート制御コンポーネントを作成しておくと便利です。
import { withAuthenticationRequired } from "@auth0/auth0-react";
import React from "react";
import { Route } from "react-router-dom";
export function ProtectedRoute({ component, ...args }: any) {
return (
<Route component={withAuthenticationRequired(component, {})} {...args} />
);
}
ルート制御ではこの ProtectedRoute
コンポーネントを使用して、ログインしていないユーザがアクセスできないページを実装できます。以下の例では、/profile
はログインしていない状態では表示できません。
import React from "react";
import { useAuth0 } from "@auth0/auth0-react";
import { Route, BrowserRouter as Router, Switch } from "react-router-dom";
import Home from "./pages/Home";
import { ProtectedRoute } from "./components/auth/ProtectedRoute";
import Profile from "./pages/Profile";
import { Layout } from "./components/layout/Layout";
import Support from "./pages/Support";
export function App() {
const { isLoading } = useAuth0();
if (isLoading) {
return <p></p>;
}
return (
<Router>
<Layout>
<Switch>
<Route path="/" exact component={Home} />
<ProtectedRoute path="/profile" component={Profile} />
<Route path="/support" exact component={Support} />
</Switch>
</Layout>
</Router>
);
}
/profile
にアクセスしようとするとログインページにリダイレクトされています。
Vercel にデプロイする
Vercel のダッシュボードから Import Project
をクリックします。
今回は GitHub にホスティングしているソースコードを元にデプロイするので、Git リポジトリを選択します。
最後にビルドコマンドと環境変数を設定します。
Auth0 の domain と clientId は環境変数に指定して React アプリに渡しましょう。
あとは Deploy ボタンをクリックして完了です。これだけでデプロイができるはずです。
サインアップ後の確認メールを SendGrid から送信する
Auth0 には Welcome メールやパスワードリセット、アカウントの検証などのためにメールを送信する仕組みが用意されています。
送信するためには事前にメールプロバイダの設定が必要です。今回は無料で提供されている SendGrid を使用してみましょう。
Email Provider の画面から SendGrid を選択し、送信元メールアドレス(From)と SendGrid の API キーを入力します。API キーは SendGrid の settings から発行できます。
ログインに成功すると以下のようなメールが送信されるようになります。
まとめ
Auth0 + Vercel + SendGrid という構成をチュートリアル的に実装し、その振る舞いを確認してみました。auth0-react
ライブラリは非常に使い勝手がよく、簡単に認証機能を組み込むことができます。一連の流れを実装しても 1 ~ 2 時間で実装できました。以前までは苦労して認証の仕組みを整えていましたが随分と楽になりそうです。