☕
Auth0のProtected Routeをreact-router-dom v6に対応させる
Auth0 React SDKを使っていたアプリが、react-router-domをv5からv6にアップデートしたら動作しなくなりました。
Auth0のブログや、サンプルコードを見て直すことになったので、修正のポイントを書いていきます。
この記事の前提
- ルーティングにreact-router-domを使用している
- ユーザ認証にAuth0 React SDKを使っている
react-router-dom v5の書き方
Auth0のサンプルコードにあるやり方ですが、カスタムのRouteコンポーネントを作って、認証が必要なパスを保護していました。
react-router-dom v5では、次のような書き方になります。
// ProtectedRoute.js
import { withAuthenticationRequired } from "@auth0/auth0-react";
import { Route } from "react-router-dom"; // v5
const ProtectedRoute = ({ component, ...options }) => {
return <Route component={withAuthenticationRequired(component, {})} {...options} />;
};
export default ProtectedRoute;
カスタムのRouteコンポーネント(ProtectedRoute)を使ったルーティングはこのようになります。
// App.js
import ProtectedRoute from './ProtectedRoute';
import { BrowserRouter, Switch, Route } from 'react-router-dom'; // v5
function App() {
return (
<BrowserRouter>
<Switch>
{/* 認証が必要なパス */}
<ProtectedRoute exact path='/' component={Home} />
{/* 認証がいらないパス */}
<Route path='/logout' component={Logout} />
</Switch>
</BrowserRouter>
);
}
export default App;
react-router-dom v6の書き方
react-router-domをv6にアップデートしてからは、記法が変わったため、以下のようにコード修正が必要になりました。
// ProtectedRoute.js
import { withAuthenticationRequired } from '@auth0/auth0-react';
function ProtectedRoute({ component }) {
const Component = withAuthenticationRequired(component, {});
return <Component />; // Routeではなく、Componentにする
}
export default ProtectedRoute;
v6になってからは、レンダリングする要素をelement
で指定するようになったため、上のコンポーネントを使用して次のように書きます。
// App.js
import ProtectedRoute from './components/ProtectedRoute';
import { BrowserRouter, Routes, Route } from 'react-router-dom'; // v6
function App() {
return (
<BrowserRouter>
<Routes>
{/* 認証が必要なパス */}
<Route index element={<ProtectedRoute component={Home} />} />
{/* 認証がいらないパス */}
<Route path="logout" element={<Logout />} />
</Routes>
</BrowserRouter>
);
}
export default App;
Auth0ProviderのonRedirectCallbackの実装
Auth0 React SDKのサンプルコードでは、認証後、ユーザのアクセスしたパスに遷移するようにコールバックが設定されています。
react-router-dom v6では、BrowserRouterの中にAuth0Providerを入れることで、同様のコールバックを実装することができます。
// Auth0Provider.js
import { Auth0Provider as Provider } from '@auth0/auth0-react';
import { useNavigate } from 'react-router-dom'; // v6
function Auth0Provider({ children }) { // 任意:カスタムのAuth0Provider
const navigate = useNavigate();
const domain = process.env.REACT_APP_AUTH0_DOMAIN;
const clientId = process.env.REACT_APP_AUTH0_CLIENT_ID;
const onRedirectCallback = (appState) => {
// navigationはBrowserRouterの中なら使用可能
navigate(appState?.returnTo || window.location.pathname);
};
...
return (
<Provider domain={domain} clientId={clientId} redirectUri={window.location.origin} onRedirectCallback={onRedirectCallback}>
{children}
</Provider>
);
}
export default Auth0Provider;
// index.js
import Auth0Provider from './hooks/Auth0Provider'; // カスタムのAuth0Provider
import { BrowserRouter } from 'react-router-dom';
import App from './App';
...
root.render(
<React.StrictMode>
<BrowserRouter>
{/* BrowserRouterの中に入れる */}
<Auth0Provider>
<App />
</Auth0Provider>
</BrowserRouter>
</React.StrictMode>
);
今回の記事は、Auth0 Developer Hubのサンプルコードを参考にしています。
Discussion