Angular SSRにAuth0を導入する
はじめに
本記事では、Angular SSRにAuth0のユニバーサルログインを追加し、特定のページへのアクセスを認証済みユーザーに限定する方法を紹介します。
まずはクライアントサイドで動作するRenderMode.Clientで認証機能を実装し、その後RenderMode.Prerenderへの対応方法までステップバイステップで説明します。
対象読者
この記事は、以下のような方を対象としています。
- AngularアプリケーションにAuth0を使った認証機能を導入したい方
- サーバーサイドレンダリング(SSR)環境下で、ログインが必要なページをプリレンダリングしたい方
Angular + Auth0の組み合わせはシンプルですが、SSRとの統合には注意点も多く、段階的な導入が重要です。
前提条件
以下のような環境を前提としています。
- Angular Universal(SSR)が導入されたプロジェクト
- ログインが必要なページ(この記事ではAuthorizedPageComponentとしています)
Auth0のセットアップ
Auth0のダッシュボードから新しいアプリケーションを作成し、以下のように設定します。
- アプリケーションの種類:シングルページアプリケーション
- 許可するCallback URL:http://localhost:4200/setting
- 許可するログアウトURL:http://localhost:4200
- 許可するWebオリジン:http://localhost:4200
作成後、ドメインとクライアントIDを控えておきます。
Angularアプリの実装
ライブラリのインストール
Auth0のAngular SDKをインストールします。
npm install @auth0/auth0-angular
Auth0の設定を追加
SDKが提供しているprovideAuth0メソッドを使って、Auth0を登録します。
SSR環境ではwindow is not definedのエラーが発生するため、ブラウザ環境でのみwindow.location.originを参照するようにしています。
import { provideAuth0 } from '@auth0/auth0-angular';
export const appConfig: ApplicationConfig = {
  // 省略
  provideAuth0({
    domain: 'YOUR_DOMAIN',
    clientId: 'YOUR_CLIENT_ID',
    authorizationParams: {
      redirect_uri:
        globalThis.window !== undefined
          ? `${window.location.origin}/setting`
          : undefined,
    },
  }),
}
Guardの追加
SDKが提供しているAuthGuardを設定します。
import { AuthGuard } from '@auth0/auth0-angular';
export const routes: Routes = [
  // 省略
  {
    path: 'setting',
    canActivate: [AuthGuard],
    component: AuthorizedPageComponent
  }
]
動作確認
/settingに遷移した際に、Auth0のログイン画面が表示されて、ログイン後にAuthorizedPageComponentが表示されたら成功。

プリレンダリングへの対応
AuthorizedPageComponentをプリレンダリングしたい場合は、SSR環境でAuthGuardが動かないようにカスタマイズする必要があります。
SSR環境を判定する方法はいくつかありますが、ここではisPlatformServer()を使っています。
import { isPlatformServer } from '@angular/common';
import { inject, PLATFORM_ID } from '@angular/core';
import { CanActivateFn } from '@angular/router';
import { AuthService } from '@auth0/auth0-angular';
import { tap } from 'rxjs';
export const cutomGuard: CanActivateFn = (route, state) => {
  const auth = inject(AuthService);
  const platformId = inject(PLATFORM_ID);
  // SSRでは認証しないのでスキップする
  if (isPlatformServer(platformId)) {
    return true;
  }
  return auth.isAuthenticated$.pipe(
    tap((loggedIn) => {
      if (!loggedIn) {
        auth.loginWithRedirect({
          appState: { target: state.url },
        });
      }
    })
  );
};
export const routes: Routes = [
  // 省略
  {
    path: 'setting',
    canActivate: [cutomGuard],
    component: AuthorizedPageComponent
  }
]
補足
ログインが必要なページで、SDKのAuthServiceから状態を取得している場合は、SSR環境でエラーが発生するためserverConfigでモックする必要があります。
import { AuthService } from '@auth0/auth0-angular';
const serverConfig: ApplicationConfig = {
  // 省略
  {
    provide: AuthService,
    useValue: {
      user$: of(),
      isAuthenticated$: of(),
    },
  },
};
まとめ
- Auth0を使うと爆速で認証機能を実装できる
- ログインが必要なページをプリレンダリングしたい場合はエラーハンドリングが必要



Discussion