目的
okta+react+openid認証 を開発環境で実施してテストする。
長いためokta設定とreact設定で分けた。前の投稿はこちら
環境
- react: 18.3.1
- react-router:5.3.4
- react-router-dom:5.3.4
- @okta.okta-react:6.9.0
- vite:6.0.5
react設定
公式GitHubレポジトリ github.com/okta/okta-react
oktaレポジトリインストール
Bash
npm install --save @okta/okta-react
BashOktaConfig.ts
oktaサーバーに接続する設定ファイルを作成する。設定ファイル.envを読み込む
src/OktaConfig.ts
const issuer = import.meta.env.VITE_APP_OKTA_ISSUER;
const clientId = import.meta.env.VITE_APP_OKTA_CLIENTID;
const redirectUri = import.meta.env.VITE_APP_OKTA_REDIRECTURI;
export interface OktaConfig {
issuer: string;
clientId: string;
redirectUri: string;
scopes: string[];
pkce: boolean
}
export const oktaConfig: OktaConfig = {
issuer: issuer,
clientId: clientId,
redirectUri: redirectUri,
scopes: ['openid', 'profile', 'email'],
pkce: true
}
TypeScript.env
.env
VITE_APP_OKTA_ISSUER=https://{oktaサブドメイン}/oauth2/default
VITE_APP_OKTA_CLIENTID=XXXXXXXXXXXXXX
VITE_APP_OKTA_REDIRECTURI=http://localhost:8080/login/callback
INIsecure-route.tsx
認証が必要なページに対して付与する
src/secure-route.tsx
import { toRelativeUrl } from "@okta/okta-auth-js";
import { useOktaAuth } from "@okta/okta-react"
import React, { useEffect, useState } from "react";
import { Route, RouteProps, useRouteMatch } from "react-router-dom";
export type SecureRouteProps = {
routeProps: RouteProps,
}
export const SecureRoute: React.FC<RouteProps> = ({ ...routeProps }) => {
const { oktaAuth, authState } = useOktaAuth();
const match = useRouteMatch();
const isPending = React.useRef(false);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
if (!match) { return; }
if (!authState) { return; }
if (authState.isAuthenticated) {
isPending.current = false;
return;
}
if (!authState?.isAuthenticated) {
if (isPending.current) { return; }
isPending.current = true;
const originalUri = toRelativeUrl(window.location.href, window.location.origin);
oktaAuth.setOriginalUri(originalUri);
oktaAuth.signInWithRedirect();
}
}, [isPending, match, oktaAuth, authState, authState?.isAuthenticated]);
if (error) {
return <div>{error.message}</div>
}
if (!authState || !authState?.isAuthenticated) {
return <div>Loading...</div>;
}
return (
<Route
{...routeProps}
/>
)
}
TSXrouters.tsx
- /
- 認証が不要なページ
- /login/callback
- これがないと認証できない
- /view
- 認証が必要なページ
src/routers.tsx
import { Route, Switch, } from "react-router-dom"
import { LoginCallback, } from "@okta/okta-react";
import { SecureRoute } from "./secure-route";
import { View, Home } from "./routes/view";
const AppRouters = () => {
return (
<Switch>
<Route path="/" exact component={Home} />
<SecureRoute path="/view" component={View} />
<Route path="/login/callback" render={() => (<LoginCallback />)} />
</Switch>
)
}
export default AppRouters;
TSXindex.tsx
src/index.tsx
import { useHistory } from "react-router-dom";
import { IonReactRouter } from '@ionic/react-router';
import AppRouters from "./routers"
import { Security } from "@okta/okta-react"
import { oktaConfig } from "@/OktaConfig";
import OktaAuth, { toRelativeUrl } from "@okta/okta-auth-js";
const oktaAuth = new OktaAuth(oktaConfig);
/** useHistoryはIonicRouter内部で使用しないとundefinedになるためwrap */
const SecurityWrapper = () => {
const history = useHistory();
const restoreOriginalUri = (_oktaAuth: unknown, originalUri: string) => {
history.replace(toRelativeUrl(originalUri || '/', window.location.origin));
};
return (
<Security oktaAuth={oktaAuth} restoreOriginalUri={restoreOriginalUri}>
<AppRouters />
</Security>
)
}
export const App = () => {
return (
<Router>
<SecurityWrapper />
</Router>
)
}
TSX以上の内容でreactアプリを立ち上げ、SecureRouteで指定されているURLを入力するとOktaの認証画面が表示される。
認証に成功すると移動したかったページに移動できる。
以上