Auth0 Single Page App SDK は、Auth0 を使用してシングルページアプリ (SPA) に認証と認可を実装するための新しい JavaScript ライブラリです。高水準の API を提供し、多くの複雑な処理を担うため、ベストプラクティスに従って SPA を保護しつつ、記述するコード量を減らせます。
Auth0 SPA SDK は、グラントやプロトコルの詳細、トークンの有効期限と更新に加え、トークンの保存とキャッシュも処理します。内部では、Universal Login と PKCE を使用した認可コードグラントフロー を実装しています。
ライブラリ と API ドキュメント は GitHub で公開されています。
新しい JavaScript SDK の使用中に問題やエラーが発生した場合は、FAQ を参照して、該当する事象が掲載されているか確認してください。
プロジェクトで Auth0 SPA SDK を使用するには、いくつかの方法があります。
- CDN から使用する:
<script src="https://cdn.auth0.com/js/auth0-spa-js/2.0/auth0-spa-js.production.js"></script>。詳細は、FAQを参照してください。
- npm を使用する:
npm install @auth0/auth0-spa-js
- yarn を使用する:
yarn add @auth0/auth0-spa-js
まず、Auth0Client クライアントオブジェクトの新しいインスタンスを作成する必要があります。アプリケーションをレンダリングまたは初期化する前に、Auth0Client インスタンスを作成してください。これは、async/await または Promise を使用して行えます。作成するクライアントインスタンスは 1 つだけにしてください。
createAuth0Client を使用すると、いくつかの処理が自動的に行われます。
Auth0Client のインスタンスを作成します。
getTokenSilently を呼び出して、ユーザーセッションを更新します。
getTokenSilently から返されるすべてのエラーを抑制します (login_required を除く) 。
Promiseを使用する
Auth0Client コンストラクターを使って、クライアントを直接作成することもできます。これは、次のような場合に便利です。
- 初期化時の
getTokenSilently の呼び出しを省略する。
- 独自のエラー処理を行う。
- SDK を同期的に初期化する。
次に、ユーザーがクリックしてログインを開始できるボタンを作成します。
<button id="login">Click to Login</button>
作成したボタンでクリックイベントをリッスンします。イベントが発生したら、使用するログイン方法でユーザーを認証します (この例では loginWithRedirect() を使用します) 。ユーザーの認証後、getUser() メソッドを使ってユーザープロファイルを取得できます。
document.getElementById('login').addEventListener('click', async () => {
await auth0.loginWithRedirect({
authorizationParams: {
redirect_uri: 'http://localhost:3000/'
}
});
//ログインしました。次のようにユーザープロファイルを取得できます:
const user = await auth0.getUser();
console.log(user);
});
Promiseを使用する
document.getElementById('login').addEventListener('click', () => {
auth0.loginWithRedirect({
authorizationParams: {
redirect_uri: 'http://localhost:3000/'
}
}).then(token => {
//ログインしました。次のようにユーザープロファイルを取得できます:
auth0.getUser().then(user => {
console.log(user);
});
});
});
API を呼び出すには、まずユーザーの を取得します。次に、そのアクセストークンをリクエストで使用します。この例では、getTokenSilently メソッドを使用してアクセストークンを取得します。
<button id="callApi">Call an API</button>
document.getElementById('callApi').addEventListener('click', async () => {
const accessToken = await auth0.getTokenSilently();
const result = await fetch('https://exampleco.com/api', {
method: 'GET',
headers: {
Authorization: 'Bearer ' + accessToken
}
});
const data = await result.json();
console.log(data);
});
document.getElementById('callApi').addEventListener('click', () => {
auth0
.getTokenSilently()
.then(accessToken =>
fetch('https://exampleco.com/api', {
method: 'GET',
headers: {
Authorization: 'Bearer ' + accessToken
}
})
)
.then(result => result.json())
.then(data => {
console.log(data);
});
});
ユーザーがクリックしてログアウトできるよう、ボタンを追加します。
<button id="logout">Logout</button>
$('#logout').click(async () => {
auth0.logout({
logoutParams: {
returnTo: 'http://localhost:3000/'
}
});
});
Auth0 SPA SDK は、デフォルトでトークンをメモリ内に保存します。ただし、この方法ではページを再読み込みした場合やブラウザータブをまたいだ場合に保持されません。代わりに、SDK の初期化時に cacheLocation プロパティを localstorage に設定すると、トークンをローカルストレージに保存できます。これにより、アクセストークンをより長く保持できるため、Auth0 のへのアクセスを妨げるブラウザーのプライバシー保護機能の影響を一部軽減できます。
ブラウザーのローカルストレージにトークンを保存すると、ページの再読み込み後やブラウザータブをまたいでも保持されます。ただし、攻撃者がクロスサイトスクリプティング (XSS) 攻撃によって SPA 上で JavaScript を実行できた場合、ローカルストレージに保存されたトークンを取得される可能性があります。XSS 攻撃の成功につながる脆弱性は、SPA のソースコードにある場合もあれば、SPA に含まれるサードパーティ製 JavaScript コード (bootstrap、jQuery、Google Analytics など) にある場合もあります。詳細は、トークンの保存を参照してください。
Auth0 SPA SDK は、ローテーション型のリフレッシュトークンを使用して、新しいアクセストークンをサイレントに取得するよう設定できます。これにより、サイレント認証時に Auth0 のセッションクッキーへのアクセスを妨げるブラウザーのプライバシー保護機能を回避できるほか、組み込みの再利用検出も利用できます。
これを有効にするには、初期化時に useRefreshTokens を true に設定します。
を SPA で使用するには、あらかじめテナントで設定しておく必要があります。
設定すると、SDK は認可ステップで offline_access スコープをリクエストします。さらに、getTokenSilently は /oauth/token エンドポイントを直接呼び出し、リフレッシュトークンをアクセストークンに交換します。
SDK は、リフレッシュトークンの保存時にストレージ設定に従います。SDK がデフォルトのインメモリストレージを使用するように設定されている場合、ページを更新するとリフレッシュトークンは失われます。
以下に、SDK の各種メソッドの使用例を示します。これらの例では jQuery を使用しています。
Auth0 の /authorize エンドポイントにリダイレクトし、Universal Login フローを開始します。
$('#loginRedirect').click(async () => {
await auth0.loginWithRedirect({
authorizationParams: {
redirect_uri: 'http://localhost:3000/'
}
});
});
ポップアップウィンドウを使用して、 ページでログインします。
$('#loginPopup').click(async () => {
await auth0.loginWithPopup();
});
ユーザーが認証フローの完了にデフォルトのタイムアウトである 60 秒以上かかると、認証は中断されます。その場合は、コード内でエラーをキャッチして、次のいずれかの対応を行う必要があります。
ユーザーに再試行を促し、error.popup.close を使用してポップアップを手動で閉じるよう案内します。
$('#loginPopup').click(async () => {
try {
await auth0.loginWithPopup();
} catch {error}
if (error instanceof auth0.PopupTimeoutError) {
// ユーザーに再試行を促すカスタムロジック
error.popup.close();
}
});
または、options オブジェクトでカスタムの popup オプションを定義します。
$('#loginPopup').click(async () => {
const popup = window.open(
'',
'auth0:authorize:popup',
'left=100,top=100,width=400,height=600,resizable'
);
try {
await auth0.loginWithPopup({ popup });
} catch {error}
if (error instanceof auth0.PopupTimeoutError) {
// ユーザーに再試行を促すカスタムロジック
error.popup.close();
}
});
ブラウザーが Auth0 から SPA にリダイレクトで戻ったら、ログインフローを完了するために handleRedirectCallback を呼び出す必要があります。
$('#loginRedirectCallback').click(async () => {
await auth0.handleRedirectCallback();
});
非表示の iframe と prompt=none を使用する方法、またはローテーションされるリフレッシュトークンを使用する方法で、新しいアクセストークンをサイレントに取得できます。リフレッシュトークンは、SDK の設定時に useRefreshTokens を true に設定した場合に使用されます。
インメモリストレージ (デフォルト) とリフレッシュトークンを使用している場合、対応ブラウザーでは Web Worker を使って新しいトークンを取得します。
$('#getToken').click(async () => {
const token = await auth0.getTokenSilently();
});
getTokenSilently() メソッドを使用するには、Dashboard の API Settings で Allow Skipping User Consent を有効にする必要があります。なお、‘localhost’ ではユーザーの同意をスキップできません。
アクセストークンは、ポップアップウィンドウを使って取得することもできます。getTokenSilently とは異なり、この方法では、サードパーティ Cookie がデフォルトでブロックされているブラウザーでもアクセストークンを取得できます。
$('#getTokenPopup').click(async () => {
const token = await auth0.getTokenWithPopup({
authorizationParams: {
audience: 'https://mydomain/api/',
scope: 'read:rules'
}
});
});
別のオーディエンス向けのアクセストークンを取得する
getTokenSilently にオプションを渡すことで、ユーザー認証時に要求したものとは異なる とスコープを持つアクセストークンを取得できます。
これはリフレッシュトークンを使用していない場合 (useRefreshTokens: false) にのみ機能します。リフレッシュトークンは、ユーザー認証時に要求された特定のオーディエンスとスコープに紐付けられているためです。
$('#getToken_audience').click(async () => {
const differentAudienceOptions = {
authorizationParams: {
audience: 'https://mydomain/another-api/',
scope: 'read:rules',
redirect_uri: 'http://localhost:3000/callback.html'
}
};
const token = await auth0.getTokenSilently(differentAudienceOptions);
});
getUser メソッドを呼び出すと、認証済みユーザーのプロファイルデータを取得できます。
$('#getUser').click(async () => {
const user = await auth0.getUser();
});
認証済みユーザーののクレームは、getIdTokenClaims メソッドを呼び出すことで取得できます。
$('#getIdTokenClaims').click(async () => {
const claims = await auth0.getIdTokenClaims();
// 生のid_tokenが必要な場合は、__rawプロパティを使って
// 取得できます
const id_token = claims.__raw;
});
logout メソッドを呼び出して、ログアウトを開始できます。
$('#logout').click(async () => {
auth0.logout({
logoutParams: {
returnTo: 'http://localhost:3000/'
}
});
});
logout メソッドを呼び出し、clientId: null を指定すると、 を指定せずにログアウトを開始できます。
$('#logoutNoClientId').click(async () => {
auth0.logout({
clientId: null,
logoutParams: {
returnTo: 'http://localhost:3000/'
}
});
});