Auth0のUsername-Password-Authenticationはデフォルトでsessionの永続化があるのでログアウトしても再ログイン時にID/パスワードを聞かれない件

# これ

![Screenshot_2023-07-11_at_10_39_00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16757/a1c05b1a-a85e-e7cb-76ff-7ce8b84f7e66.png)



# 問題

ログアウトしてもログアウトしてない。
下の画像のようにAuth0はデフォルトでsessionを永続化するので、ログアウトしても再ログイン時にIDとパスワードの再入力が求められずいきなりログインできる。

![Screenshot_2023-07-11_at_10_06_51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16757/ad56a104-b33f-fc97-625b-e230c9a52424.png)


携帯などの個々人保有端末なら問題ないが、公共のパソコンなどでログインしたりするとかなりマズい。
（パソコン1台で家族間で同じサイトにログインするとかもあるし）

ログアウトしてもログアウト出来てないから、**別IDでログイン出来ないのはすごく非直感的動作**。


# 解決

上の画像の設定を`Non-Persistent Session`にすれば解決しそうだが、そうでもない。

https://auth0.com/docs/manage-users/sessions/non-persistent-sessions

> Browser Limitations
In some cases, non-persistent sessions cannot be enforced by tenant settings. Examples include:
> 
> - The user has a session restore setting on the browser enabled; restoring the session also restores the session cookie.
> 
> - The user closes a tab but not the browser window; the session cookie is not cleared until the session ends based on Idle or Absolute Expiration.

要はブラウザーによりけりでこの動作は保証されない。

https://community.auth0.com/t/non-persistent-sessions-not-working/87201

Auth0の中の人も

> この設定があったとしてもOSXだとcommand + Qで確実にアプリケーションを落とさないとセッションが維持される

とも言ってる。

# どうするのか？

https://community.auth0.com/t/log-out-doesnt-work-and-automatically-sign-in/14826/3

`auth0 api /v2/logout`を叩けと言ってる。

https://auth0.com/docs/api/authentication?http#auth0-logout

> GET https://{yourDomain}/v2/logout?client_id={yourClientId}&returnTo=LOGOUT_URL

1. client_id
1. returnTo

これら2つの有無パターンがある。

> - If the client_id parameter is included, the returnTo URL must be listed in the Allowed Logout URLs set at the application level (see Setting Allowed Logout URLs at the App Level).
> - If the client_id parameter is NOT included, the returnTo URL must be listed in the Allowed Logout URLs set at the tenant level (see Setting Allowed Logout URLs at the Tenant Level).
> - If the client_id parameter is included and the returnTo URL is NOT set, the server returns the user to the first Allowed Logout URLs set in the Dashboard (see Setting Allowed Logout URLs at the Tenant Level).

- `client_id`を含めるなら、`returnTo`はテナント内のApp内の`Allowed Logout URLs`で設定したURLしかだめ
- `client_id`を含め**ない**なら、`returnTo`はテナントの`Settings > Advanced`の`Allowed Logout URLs`で設定したURLしかだめ
- `client_id`があって、`returnTo`が無いならテナント内のApp内の`Allowed Logout URLs`で設定した最初のURLに飛ばす

`client_id`をユーザー側（ブラウザ側）から見えるのはなんとなくモヤモヤするので、

> GET https://{yourDomain}/v2/logout?returnTo=LOGOUT_URL
（client_id削除）

こう呼ぶとして、`returnTo`はテナントの`Settings > Advanced`の`Allowed Logout URLs`で設定したURLにする。

![Screenshot_2023-07-11_at_10_43_47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16757/356493cf-85ef-0234-6ead-33e32d6d4668.png)


## NextAuth.jsからだとどうするか？

https://www.npmjs.com/package/next-auth

自分は`NextAuth.js`からAuth0をProviderとして使っているので、更に問題が厄介で

```js
// ログアウトしたら完全にログアウトするためにAuth0のlogoutAPIを叩く
signOut({
  callbackUrl: "https://{yourDomain}/v2/logout?returnTo=LOGOUT_URL",
})
```

と単純にしても機能しない。


https://next-auth.js.org/configuration/callbacks#redirect-callback

> By default only URLs on the same URL as the site are allowed, you can use the redirect callback to customise that behaviour.

> デフォルトだと、callbackUrlは同じサイト内のURLにしか飛ばさないよ。

なので、違うサイトのやつは無視して`baseUrl`（トップページ）へ飛ばされる。

```js
callbacks: {
  async redirect({ url, baseUrl }) {
    // こういったものを追加する
    if (url.includes("auth0.com/v2/logout")) {
      return url
    }

    // https://next-auth.js.org/configuration/callbacks#redirect-callback
    // のコピー
    // Allows relative callback URLs
    if (url.startsWith("/")) return `${baseUrl}${url}`
    // Allows callback URLs on the same origin
    else if (new URL(url).origin === baseUrl) return url
    return baseUrl
  },
}
```

ここまでするとやっと再ログイン時にID、パスワードを聞かれるようになる...

1. サインアウトボタンを押す
1. signOut()を呼ぶ
1. callbackUrlへ行こうとする
1. redirectでurlが処理される
1. 自分が追加したコード部分`url.includes("auth0.com/v2/logout")`により直接urlへリダイレクト出来る
1. Auth0のログアウトAPIを叩く
1. 完全にAuth0からログアウト出来る
1. returnToへ移動する


# まとめ（NextAuth.js + Auth0 provider）

1. Non-Persistent Sessionにする必要は特にない
1. テナントの`Settings > Advanced`の`Allowed Logout URLs`を設定する（ログアウトして戻る場所）
1. [Redirect callback][1]を書き換える
1. [singOutのcallbackUrl][2]を追加し、Auth0のLogout APIを叩くようにする
    - returnToは2.で設定したもの



[1]: https://next-auth.js.org/configuration/callbacks#redirect-callback
[2]: https://next-auth.js.org/getting-started/client#specifying-a-callbackurl-1