0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

SPA の localhost 起動時、 Auth0 認証経由の API 実行が Consent Required エラーになってしまうのを回避する

Posted at

はじめに

以前書いた、Auth0 サンプルの SPA を微修正して、 Auth0 サンプルの API に CORS していく では、Auth0 のログイン設定にて audience 設定をしていました。

src/main.ts
app
  .use(hljsVuePlugin)
  .use(createRouter(app))
  .use(
    createAuth0({
      domain: authConfig.domain,
      clientId: authConfig.clientId,
      authorizationParams: {
        redirect_uri: window.location.origin,
        audience: authConfig.audience // <-- 追加してたとこ
      }
    })
  )

しかし、ふと疑問が。

「では単一のページ (SPA) から複数の対向 API 実行したかったらどうするんだ?」
(当然発生するケース)

で、それ自体は簡単だったのですが、今度はそれを localhost で検証する場合に若干面倒だということがわかったので、その解消方法について備忘録がてら残しておこうと思います。

複数の対向 API を実行したい場合に何を変更すればよいか?

例えば前回の例だと http://localhost:3000 にて vite で起動したサーバーから、 http://localhost:8080 のみに API実行してました。

今回は、 http://locahlhost:8080 , http://locahlhost:8081 の2箇所に API 実行したいと思います。

で、結論から書くと、実装自体は非常にシンプルです。以下でできます。

src/main.ts
app
  .use(hljsVuePlugin)
  .use(createRouter(app))
  .use(
    createAuth0({
      domain: authConfig.domain,
      clientId: authConfig.clientId,
      authorizationParams: {
        redirect_uri: window.location.origin,
        // audience: authConfig.audience <-- ここを削除
      }
    })
  )

↓はベタなコードですいません。サンプルの改造に力入れてもしょうがないんで :sweat:

src/views/Practice.vue
<template>
  <div>
    {{ token }}
    <hr/>
    Response from 8080: {{ response1 }}
    <hr/>
    Response from 8081: {{ response2 }}
  </div>  
</template>

<script setup lang="ts">
import { onMounted } from 'vue';
import { useAuth0 } from '@auth0/auth0-vue'
import { ref } from 'vue'
import axios from 'axios'

const { getAccessTokenSilently } = useAuth0()
const token = ref('')
const response1 = ref({})
const response2 = ref({})
const options = ref({})

import authConfig from "../../auth_config.json";
onMounted(async () => {
  token.value = await getAccessTokenSilently({
    authorizationParams: {
        audience: authConfig.audience_1
    }
  })
  options.value = {
    headers: {
      Authorization: `Bearer ${token.value}`
    }
  }

  var temp = await axios.get('http://localhost:8080/authorized', options.value)
  response1.value = temp.data.message

  token.value = await getAccessTokenSilently({
    authorizationParams: {
        audience: authConfig.audience_2
    }
  })
  options.value = {
    headers: {
      Authorization: `Bearer ${token.value}`
    }
  }

  temp = await axios.get('http://localhost:8081/authorized', options.value)
  response2.value = temp.data.message
})
</script>

getAccessTokenSilentlyAuthorizationParams を書いてあげるだけですね。

しかしながら、これを単に実行すると Consent Required というエラーになり、2回目の API (to localhost:8081 がエラーになるはずです。

で、これをどうやって解消するんだ?...って話です。

解決策は https 化して、かつ localhost でなくアクセスすれば OK らしい

本現象の根本原因は こちら のようです。

どうやら初回はログイン済みセッションから OAuth 同意画面を SKIP できているようですが、その次の同意画面をSKIP できないということなのかなと解釈しました。
(first party, third party ってのは OAuth の用語なのか Auth0 の用語なのかよくわかってませんが。なんにしてももうちょっと勉強しないとです...)

では上記のページに記載があるように /etc/hosts とかにエントリ追加して localhost じゃなくせばいいじゃない?となるんですが、今度はこちらが問題となります。

Why do I get auth0-spa-js must run on a secure origin?

これをサマリすると、 auth0-spa-js が動くためには、以下の URL じゃなきゃだめだよと言ってます。

  • https なURLでの接続
  • localhost 的なニュアンスのなにか

これと先程の課題の AND を取ると、

https かつ localhost じゃない URL でアクセスすればいいじゃない」ということになりますね。

ということで、以下の対応をしました。

/etc/hosts にエントリ追加

どうせならさっきのページに書かれた感じでエントリ追加してみましょう。

##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1	myapp.example <-- 追加
255.255.255.255	broadcasthost
::1             localhost

mkcert を使って https

viteでhttpsなlocalhostを起動する が大変参考になりました。ありがとうございます。

やったことは以下です。

% brew install mkcert

% cd /path/to/SPA のある場所

% mkcert -install
Created a new local CA 💥
Sudo password:
The local CA is now installed in the system trust store! ⚡️

% mkcert localhost

Created a new certificate valid for the following names 📜
 - "localhost"

The certificate is at "./localhost.pem" and the key at "./localhost-key.pem" ✅

It will expire on 1 May 2027 🗓

% ls *.pem
localhost-key.pem  localhost.pem

ここで作成されたファイルを、 SPA の vite.config.js に読み込みます。

vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import fs from 'fs' // <-- 追加

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  // ここから下を追加
  server: {
    https: {
      key: fs.readFileSync('./localhost-key.pem'),
      cert: fs.readFileSync('./localhost.pem'),
    }
  }
})

以下も実施。

npm install --save-dev @types/node

最後に Auth0 Dashboard で、SPA に関する以下の URL を書き換えておきます。
(もともとは http://localhost:3000 になっているはず)

  • Allowed Callback URLs
  • Allowed Logout URLs
  • Allowed Web Origin

image.png

ここまで完了したら、8080, 8081 の API と、SPA の vite を起動し、ブラウザから https://myapp.example:3000/#/practice に接続します。

image.png

Consent Required が回避できているのがわかります。

まとめ

ということで、複数の対向 API を持つ SPA を localhost で開発する際に発生する Consent Requied 問題が発生することを、以下にて回避することができました。

  • audience 定義場所の変更
  • hosts へのエントリ追加
  • vite サーバーの https 化

次はユーザアクセスのブロックや RBAC 周りを勉強していこうと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?