3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Auth0に登録されているSMS認証用の電話番号を更新する

Last updated at Posted at 2020-02-07

Auth0の多要素認証としてSMS認証を設定している場合、ユーザー自身が電話番号を更新できたほうが良いと思ったので、前回のログインID(メールアドレス)の変更に続いてSMS認証用の電話番号の更新方法を考えてみました。

※この記事で言うSMS認証用の電話番号はOIDCで定義されている標準クレームのphone_numberとは別物です。

電話番号変更の基本的な流れ

シーケンス図にするとこんな感じです。

change_sms_authenticator.png

クライアントアプリにSMS認証用の電話番号の一覧を表示する画面を用意して、そこから電話番号の追加/削除ができるイメージで考えました。

操作手順

今回はアプリ実装ではなく、コマンラインベースで動作を確認しています。

事前準備

クライアントとなるアプリのAuth0設定を変更します。
DashBoard > Applications > 対象のクライアントアプリを選択し、設定画面の下の方にある
Advanced SettingsのGrant Typesメニューの中にあるMFAのチェックボックスにチェックを入れます。

MFA情報更新用アクセストークンを取得

ユーザーのMFAに関する情報を参照したり更新するためには、https://{Auth0のドメイン}/mfa/へのアクセス権が必要なので、Auth0を使ってログインをするときの認可リクエストにaudiencescopeパラメーターを追加します。

  • audience
    • https://{Auth0のドメイン}/mfa/
  • scope
    • enroll
    • read:authenticators
    • remove:authenticators
Node.js(Express.js)での認可リクエスト例
const querystring = require('querystring');

const params = {
  audience: 'https://{Auth0のドメイン}/mfa/',
  scope: 'openid enroll read:authenticators remove:authenticators',
  response_type: 'code',
  client_id: '{クライアントID}',
  state: '{state}',
  redirect_uri: '{リダイレクト先}',
  nonce: '{nonce}',
};

res.redirect(
  `${`https://{Auth0のドメイン}/authorize/`
    + '?'}${
    querystring.stringify(params)}`,
);

普段Auth0にログインするときと同じ流れなので手順は省略しますが、最終的に以下のようなトークンが取れればOKです。

IDトークンのペイロード

{
  "iss": "https://.../",
  "sub": "auth0|5e4b...",
  "aud": [
    "https://.../mfa/",
    "https://.../userinfo"
  ],
  "iat": 1581248735,
  "exp": 1581249335,
  "azp": "K3S6Uk...",
  "scope": "openid enroll read:authenticators remove:authenticators"
}

アクセストークン(JWT)のペイロード

{
  "iss": "https://.../",
  "sub": "auth0|5e4b...",
  "aud": [
    "https://.../mfa/",
    "https://.../userinfo"
  ],
  "iat": 1581248735,
  "exp": 1581249335,
  "azp": "...",
  "scope": "openid enroll read:authenticators remove:authenticators"
}

トークンの有効期限

IDトークンとアクセストークンのiatexpを見るとわかりますが
audienceにhttps://{Auth0のドメイン}/mfa/が含まれているとトークンの有効期限が10分になります。
以降の処理は10分以内に完了させないと、トークンの有効期限切れで途中で失敗するので、その場合は最初からやり直す必要があります。

登録済み電話番号の一覧を取得

アクセストークンを使って登録済み電話番号を取得します。

Request
GET https://{Auth0のドメイン}/mfa/authenticators HTTP/1.1
Content-Type: application/json
Authorization: Bearer {アクセストークン}

登録済みの電話番号に加えて、最初に電話番号を登録したときに表示されるリカバリーコードの情報が取得できます。

Response
[
  {
    "id": "recovery-code|dev_iBNU...",
    "authenticator_type": "recovery-code",
    "active": true
  },
  {
    "id": "sms|dev_M38ers...",
    "authenticator_type": "oob",
    "active": true,
    "oob_channel": "sms",
    "name": "+81 XXXXXXXXXXX"
  }
]

電話番号の追加登録

ユーザーに入力してもらった電話番号を登録します。

Request
POST https://{Auth0のドメイン}/mfa/associate HTTP/1.1
Content-Type: application/json
Authorization: Bearer {アクセストークン}

{
  "client_id": "{クライアントID}",
  "client_secret": "{クライアントシークレット}",
  "authenticator_types": ["oob"],
  "oob_channels": ["sms"],
  "phone_number": "+81 XXXXXXXXXXX"
}
Response
{
  "authenticator_type": "oob",
  "binding_method": "prompt",
  "oob_channel": "sms",
  "oob_code": "Fe26.2*7fzi84..."
}

oob_codeはこの後の電話番号のアクティベートで使用するので控えておきます。

ちなみに、ここまでの状態で再度GET /mfa/authenticatorsを叩いて電話番号を取得すると以下のようなレスポンスが返ってきます。

[
  {
    "id": "recovery-code|dev_iBNU...",
    "authenticator_type": "recovery-code",
    "active": true
  },
  {
    "id": "sms|dev_M38ers...",
    "authenticator_type": "oob",
    "active": true,
    "oob_channel": "sms",
    "name": "+81 XXXXXXXXXXX"
  },
  // ↓追加した電話番号
  {
    "id": "sms|dev_qFCdZ...",
    "authenticator_type": "oob",
    "active": false,
    "oob_channel": "sms",
    "name": "+81 XXXXXXXXXXX"
  }
]

今追加した電話番号はSMS送信の疎通確認ができていないのでactiveがfalseになっています。

補足:初めて電話番号を登録する場合

もしもユーザーが電話番号をひとつも登録していない状態でPOST /mfa/associateを叩くと、リカバリーコードを含んだレスポンスが返ってきます。この場合はユーザーにリカバリーコードを提示しましょう。

{
  "authenticator_type": "oob",
  "binding_method": "prompt",
  "recovery_codes": [
    "E54JQ..."
  ],
  "oob_channel": "sms",
  "oob_code": "Fe26.2*2dcSxXwo..."
}

電話番号のアクティベート

ここまでのAPIリクエストでユーザーが入力した電話番号に対してSMSが送信されているはずなので、SMSに記載されているワンタイムパスワードを入力してもらいます。
これでSMSの疎通確認が完了するので、SMS認証でこの電話番号が使えるようになります。

Request
POST https://{Auth0のドメイン}/oauth/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded

client_id={クライアントID}&client_secret={クライアントシークレット}&mfa_token={アクセストークン}&grant_type=http%3A%2F%2Fauth0.com%2Foauth%2Fgrant-type%2Fmfa-oob&oob_code={oob_code}&binding_code={OTP}

見辛いので使用しているパラメータを列挙します。

  • client_id
  • client_secret
  • mfa_token -> MFA情報更新用のアクセストークン
  • grant_type -> http://auth0.com/oauth/grant-type/mfa-oob
  • oob_code -> POST /mfa/associateのレスポンスに含まれていたoob_code
  • binding_code -> SMSで送信されたワンタイムパスワード
Response
{
  "access_token": "eyJhNc0l...",
  "scope": "enroll read:authenticators remove:authenticators",
  "expires_in": 600,
  "token_type": "Bearer"
}

これで電話番号の登録は完了です。

登録済みの電話番号を削除

GET /mfa/authenticatorsで取得したID(sms|〜で始まるやつ)を指定して電話番号を削除します。

Request
DELETE https://{Auth0のドメイン}/mfa/authenticators/{id} HTTP/1.1
Authorization: Bearer {アクセストークン}

電話番号の削除処理はこれだけです。

補足:電話番号を全て削除した場合

activeな電話番号を全て削除してしまい、ユーザーが保持するauthenticatorがリカバリーコードだけになると、次ログインするときにID/パスワード入力後のSMS認証でリカバリーコードの入力を求められます。
スクリーンショット 2020-02-07 18.40.45.png

こんなふうに

電話番号が複数登録されているときのSMS認証

電話番号が複数登録されているとSMS認証のときにSMS送信先の電話番号を選択できるようになります。

スクリーンショット 2020-02-07 18.50.17.png

電話番号の左に表示される>をクリックすると

スクリーンショット 2020-02-07 18.41.24.png

SMSの送信先を選択できるようになりました!

このやり方でSMS認証用の電話番号のセルフメンテ機能が実現できそうです。

3
1
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
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?