EventBridgeから直接Auth0 APIを実行してユーザ情報を更新してみた(OAuth Client Credentials)

2021.08.10

どうも!オペレーション部の西村祐二です。

2021年3月頃、EventBridgeがAPI Destinations(APIの送信先)をサポートし、イベントルールのターゲットにHTTPのエンドポイントを指定できるようになりました。

【アップデート】EventBridgeのターゲットにHTTPのエンドポイントが指定可能になったので、EventBridgeから直接SlackのAPIを叩いてみた | DevelopersIO

この機能を紹介している情報のほとんどがAPI KeyやBasic認証を使った場合でOAuth Client Credentialsを使った場合がほとんどなかったので、今回、Authorization TypeをOAuth Client Credentialsに設定し、外部APIとしてAuth0 APIを実行しユーザ情報を更新する方法を紹介したいと思います。

Auth0側の設定

2021年8月10日現在、EventBridgeがサポートしているOAuthのフローはClient Credentials flowだけなので、そのフローに沿った設定を行っていきます。

Auth0のドキュメントは下記です。

https://auth0.com/docs/flows/call-your-api-using-the-client-credentials-flow#steps

M2Mアプリケーションを作成

まず、Auth0のコンソールからM2Mアプリケーションを作成していきます。

今回名前は「test-m2m」としています。

今回、Management APIを使ってユーザ情報を更新する想定なので、紐付けるAPIは「Auth0 Management API」を選択します。

また、動作確認が目的なためPermissionsはALLにしておきます。本番環境で利用する際は必要な権限だけ設定してください。

作成が完了したら、Domain, Client ID, Client Secretをメモしておいてください。

これでAuth0側の設定は完了です。

EventBridge側の設定

Connectionの作成

まず、Auth0 Management APIを実行するためのトークンを取得するConnectionを作成します。

Auth0のドキュメントを確認しながら項目を埋めていきます。今回、名前を「auth0-OAuth」としています。

設定項目を下記に記載しておきます。

  • Authorization Type
    • OAuth Client Credentials
  • Authorization endpoint
    • https://<コピーしたドメイン>/oauth/token
  • HTTP method
    • POST
  • Client ID
    • コピーしたClient ID
  • Client secret
    • コピーしたClient Secret

OAuth Http Parameters

  • Parameter
    • Header
  • Key
    • content-type
  • Value
    • application/json
  • Parameter
    • Body field
  • Key
    • audience
  • Value
    • Auth0 Management APIのAPI Audience

Auth0のコンソールでいうところのAPIsのこの値

  • Parameter
    • Body field
  • Key
    • grant_type
  • Value
    • client_credentials

設定が入力できたらCreateボタンをクリックして作成します。

もし、作成時にエラーがでた場合、言語設定を英語設定に設定変更したらいけるかもしれません。

作成後、Connection「auth0-OAuth」のステータスがAuthorizedになっていればOKです。

API destinationを作成

実行したいAPIを設定するAPI destinationを作成していきます。

Auth0 Management APIを使ってユーザ情報を更新するAPIを実行する設定をしています。

Auth0のAPIドキュメントを参考に設定していきます。

名前は今回「auth0-update-user」として設定しています。

設定項目について簡単に説明します。

  • API destination endpoint
    • 実行したいAPIのエンドポイントを指定します。今回実行したいエンドポイントの/api/v2/users/{id}のパスパラメータid部分は受け取ったイベントからidを取得し、設定するため「※」にしています。
  • HTTP method
    • 実行したいAPIのメソッドを指定します。
  • Connection
    • 先程作成した「auth0-OAuth」を指定します。

設定が入力できたらCreateボタンをクリックして作成します。

もし、作成時にエラーがでた場合、言語設定を英語設定に設定変更したらいけるかもしれません。

Ruleを作成

これまで作成したものを組み合わせて特定のイベントをEventBridgeが受け取ったら設定したAuth0のAPIを実行するルールを作成していきます。

ルール名はユーザのメタデータを更新する意味で「update-user-metadata」にしています。

発火条件のイベントパターンはカスタムイベントとしてテスト用のイベントに発火するようにしています。

今回、defaultのevent busを利用するように設定しています。

受け取ったイベントをもとに実行するターゲットを設定します。先程作成したAPI destinationを指定します。

  • Path Parameters

$.detail.id

受け取ったイベントは仕様的にdetailが含まれ、そこに必要なデータが入っているため、そのデータのidを取得して「*」に設定する意味になります。

※この値はurlエンコードされないまま?外部APIが実行されるため、イベントデータに予めエンコードした形で含む必要があるようです。

  • Configure input

受け取ったイベントのdetailに含まれるuser_metadatametadataとして受け取るよ、という意味になります。

{
  "metadata": "$.detail.user_metadata"
}

上で受け取った値metadataを使ってbodyを下記のように設定するよ、という意味になります。

{
  "user_metadata": <metadata>
}

設定が入力できたらCreateボタンをクリックして作成します。

もし、作成時にエラーがでた場合、言語設定を英語設定に設定変更したらいけるかもしれません。

これでEventBridge側の準備完了です。

動作確認

設定ができたので実際にイベントを発行して、動作確認してみます。

今回、cliからイベントを発行します。

コマンドは下記です

aws events put-events --entries file://test.json

発行するイベントは下記としています。

test.json

[{
    "Source": "com.mycompany.myapp",
    "DetailType": "myDetailType",
    "Detail": "{ \"id\": \"google-oauth2%7C000000000000000000000\", \"user_metadata\": { \"profileCode\": 1479 } }",
    "EventBusName": "default"
}]

Auth0のidはパスパラメータに設定するため、urlエンコードした形でセットします。

google-oauth2|000000000000000000000

google-oauth2%7C000000000000000000000

更新するユーザのメタデータはprofileCodeを1479に設定するようにしています

{
  "user_metadata": { "profileCode": 1479 }
}

コマンド実行時の成功ログ

{
    "FailedEntryCount": 0,
    "Entries": [
        {
            "EventId": "xxxxxxx-xxxxx-xxxx-xxxx-xxxxxxxxxx"
        }
    ]
}

処理が正常に成功すると、Auth0に登録されているユーザのuser_metadataが更新されます。

最後にAuth0側で記録されたRAWログを掲載しておきます。userAgentがAmazon/EventBridge/ApiDestinationsとなってEventBridgeから更新されたことがわかります。

{
  "date": "2021-xx-xxTxx:xx:xx.xxxZ",
  "type": "sapi",
  "description": "Update a User",
  "client_id": "xxxxxxxxxxxxxxxxxxxxxxxx",
  "client_name": "",
  "ip": "xxxxxxxxxxxxx",
  "user_agent": "Other 0.0.0 / Other 0.0.0",
  "details": {
    "request": {
      "method": "patch",
      "path": "/api/v2/users/google-oauth2%7C000000000000000000000",
      "query": {},
      "userAgent": "Amazon/EventBridge/ApiDestinations",
      "body": {
        "user_metadata": {
          "profileCode": 1479
        }
      },
      "channel": "api",
      "ip": "xxxxxxxxxxxx",
      "auth": {
        "user": {},
        "strategy": "jwt",
        "credentials": {
          "scopes": [
						...
          ]
        }
      }
    },
    "response": {
      "statusCode": 200,
      "body": {
        "email": "xxxxxxxxxxxxxxxxxxx",
        "email_verified": true,
        "name": "xxxxxxxx",
        "given_name": "xxx",
        "family_name": "xxxxx",
        "picture": "xxxxxxxxxxxxxxxxxxx",
        "locale": "ja",
        "updated_at": "2021-xx-xxTxx:xx:xx.xxxZ",
        "user_id": "google-oauth2|000000000000000000000",
        "nickname": "xxxxxxxxxxxxxxxxxxx",
        "identities": [
          {
            "provider": "google-oauth2",
            "access_token": "xxxxxxxxxxxxxxxxxxx",
            "expires_in": xxxx,
            "user_id": "xxxxxxx",
            "connection": "google-oauth2",
            "isSocial": true
          }
        ],
        "created_at": "2021-xx-xxTxx:xx:xx.xxxZ",
        "user_metadata": {
          "profileCode": 1479
        },
        "last_ip": "xxxxxxxxxxxxxxxxxxx",
        "last_login": "2021-xx-xxTxx:xx:xx.xxxZ",
        "logins_count": 14
      }
    }
  },
  "log_id": "000000000000000000000",
  "_id": "000000000000000000000",
  "isMobile": false
}

さいごに

今回、Authorization TypeをOAuth Client Credentialsに設定し、外部APIとしてAuth0 APIを実行してユーザ情報を更新する方法を紹介しました。

正直、調べてもあまり情報がなく、EventBridgeから外部APIを実行したときのリクエスト内容やレスポンスが見れない(みつけれてないだけ?)のでかなり時間がかかりました。

誰かの参考になれば幸いです。

参考サイト

(Securely!) Deliver native AWS events to any HTTP destination with EventBridge API Destinations