SPAの認証はみんな地獄だと思っていた:localStorageのルーレット、セッションクッキーの杖、果てしないCSRFダンス。だがAngularとReactでOpenID Connect(OIDC)認証を統合? これが大どんでん返しだ。シナリオが一変する——セキュアで標準的、ブラウザにシークレットが漏れない。アプリは単にユーザーをログインさせるだけじゃなく、中央集権崩壊のAIだらけのウェブに備えられる。
OIDCはバズワードの寄せ集めじゃない。OAuth 2.0にIDを乗っけたもの、「Googleでログイン」の裏側だ。シングルページアプリでは認可コードフロー + PKCEが王者。クライアントシークレットがブラウザに露出する心配なし。傍受の悪夢もなし。Okta、Auth0、Keycloakからの純粋なプロバイダ無視のマジックだ。
OIDC + PKCEがウェブ認証の月面着陸級な理由
従来のSPA認証を画面ドアに南京錠をテープで貼ったようなものだと思うがいい——見た目は固そうだが最初の風で終わり。PKCE? ワンタイムコード生成付きの金庫扉だ。専門家直々の決め手はこれだ:
SPAでは、認可コードフロー + PKCEが最もセキュアで推奨される。理由は: - ブラウザにクライアントシークレットが露出しない - 認可コード傍受から守る - 現代のIDプロバイダ(Okta、Auth0、Azure AD、Keycloak、Google)と互換
ドカン。OAuth 2.1準拠で全ピットフォール回避。メモリ保存トークン(localStorageのXSS餌さよなら)、自動発見ドキュメント、openid profile emailのスコープ。アプリは必要な分だけ取る。
俺の熱い見解で誰も触れない独自視点:これは90年代のHTTPからHTTPSへのシフトそっくり。当時は平文ログインをみんな無視、今OIDCがIDのHTTPSだ。大胆予測? 5年後、AIエージェントがSPAをデジタルノマドみたいに飛び回る時代、OIDCパスポート必須。ReactダッシュボードがAIアナリストとチャット? これなしじゃ無理だ。
まずは前提。IdPを起動——Oktaでも何でも。SPAクライアント作成:issuer URL、client ID、リダイレクトURI(Angularはlocalhost:4200/auth/callback、Reactは:3000)。パブリック、PKCE有効、シークレットなし。スコープはopenid profile email、APIも追加でオシャレに。
Angularセットアップ:光速セキュアログイン
Angular勢、喜べ。angular-oauth2-oidcが戦歴十分の相棒——成熟したノンフリル本番仕様。
Npmでぶち込め:npm i angular-oauth2-oidc。次にauth.config.ts:
import { AuthConfig } from 'angular-oauth2-oidc';
export const authConfig: AuthConfig = {
issuer: 'https://YOUR_ISSUER',
clientId: 'YOUR_CLIENT_ID',
redirectUri: window.location.origin + '/auth/callback',
postLogoutRedirectUri: window.location.origin + '/',
responseType: 'code',
scope: 'openid profile email',
strictDiscoveryDocumentValidation: false,
showDebugInformation: true,
requireHttps: false,
};
サービスだ——auth.service.ts。OAuthServiceインジェクト、設定、サイレントリフレッシュ、ディスカバリロード、ログイン試行。ログインでコードフロー発動、アウトでホームへ。ログイン中? hasValidAccessToken()で。トークンクレーム? すぐそこだ。
async init(): Promise<void> {
this.oauthService.configure(authConfig);
this.oauthService.setupAutomaticSilentRefresh();
await this.oauthService.loadDiscoveryDocumentAndTryLogin();
}
App.module.ts? APP_INITIALIZERでinit呼び出し。OAuthModule.forRootにresourceServerでAPIトークンパススルー。ルートに/auth/callback——空スピナーコンポーネント。ガード? CanActivateでログイン確認、ダメならリダイレクト。
canActivate(): boolean {
if (!this.auth.isLoggedIn) {
this.auth.login();
return false;
}
return true;
}
ダッシュボード保護完了。Angularアプリは要塞化——トークンがバックエンドコールに自動付与。ふと思う:AIプラグインがこのフローで自動認証とか。未来派の燃料だ。
ああ、ローカルdevでhttp? requireHttps: false。Prod? ガチガチに。
React:OIDCのエレガント無駄なし
React組——react-oidc-context on oidc-client-ts。軽量、hooks優先の至福。
Npm:npm i react-oidc-context。アプリをwrap:
Provider設定はAngularミラー——issuer、client_id、redirect_uri: window.location.origin + ‘/auth/callback’、response_type: ‘code’、scope、post_logout_redirect_uri。
const oidcConfig = {
authority: 'https://YOUR_ISSUER',
client_id: 'YOUR_CLIENT_ID',
redirect_uri: `${window.location.origin}/auth/callback`,
post_logout_redirect_uri: window.location.origin,
response_type: 'code',
scope: 'openid profile email',
};
const oidcProviderConfig = {
client: oidcConfig,
onSigninCallback: () => {
window.history.replaceState({}, document.title, window.location.pathname);
},
};
<App oidcConfig={oidcProviderConfig} />
Hooks満載:useAuthでisAuthenticated、user、signinRedirect、signoutRedirect。ルート保護? 条件レンダーかwrapper。
const { isAuthenticated, user, signinRedirect, signoutRedirect } = useAuth();
if (!isAuthenticated) {
return <button onClick={() => signinRedirect()}>Log in</button>;
}
APIコール? インターセプターでauth状態からaccess_token取って。コールバックルート? シンプルdiv、history.replaceStateでURLクリーン。
Reactのフローは軽い——Angularのモジュールよりボイラープレート少なめ。パワー? 同等。メモリトークン、サイレントリニュー動く。Create React Appがエンタープライズ級だ。
SPA開発者にとってこれが大事な理由
短く:大規模XSS耐性。localStorage? 泥棒の餌。メモリトークン? リフレッシュで消え、サイレント更新。
長く? IdPディスカバリドキュメントでプロバイダ換装ゼロコード変更。今日Google、明日Auth0——抜き差し自在。
セキュリティ小言:IdPは「スムーズ」煽るが、prodでstrictDiscoveryDocumentValidation: trueでissuer不一致キャッチ。寝てんなよ。
未来派視点:AI爆発中——エージェン