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