リフレッシュトークンの取り消し

リフレッシュトークンが侵害された場合に備えて、リフレッシュトークンを取り消すことができます。Auth0は、トークンが悪意のある攻撃者にさらされている可能性があるかのように、トークンの失効を処理します。

また、クライアントが新しいアクセス トークンを取得するためにリフレッシュトークンを交換するたびに、新しいリフレッシュトークンも返されるように、リフレッシュトークンのローテーションを使用することもできます。このため、侵入を受けると永久にリソースへのアクセスを許してしまうような、寿命の長いリフレッシュトークンはなくなりました。リフレッシュトークンは交換され続け、失効し続けるため、脅威の軽減に繋がっています。

次の方法でリフレッシュトークンを無効化することができます。

  • ダッシュボード内

  • 認証/oauth/revokeエンドポイントにPOST要求を行う

  • Management API/api/v2/device-credentialsエンドポイントにPOST要求を行う

トークンと付与を更新する

付与により、アプリケーションはユーザー資格情報を公開することなく、別のエンティティ上のリソースにアクセスできるようになります。トークンは付与の文脈で発行され、付与が無効化されると、その付与の文脈で発行されたすべてのトークンも無効化されます。一方、トークンが無効化された場合、必ずしも付与が無効化されるわけではありません。

DashboardまたはManagement APIを使用して、デバイスがAuth0のユーザーからリンク解除されたときに、Dashboardのテナント設定で取り消し動作を選択できます。

  1. Go to [Dashboard] > [Tenant Settings(テナント設定)] > [Advanced(詳細)]に移動し、[Settings(設定)]セクションにスクロールします。

  2. 失効をどのように動作させたいかに応じて、リフレッシュトークン失効削除許可トグルを有効または無効にします。

    1. リフレッシュトークンを無効化する際に基礎となる許可を削除するには、トグルを有効にします。取り消し要求ごとに、特定のトークンだけでなく、同じ認可付与に基づくその他すべてのトークンを無効にします。つまり、同じユーザー、アプリケーション、オーディエンスに発行されたリフレッシュトークンがすべて取り消されます。

    2. リフレッシュトークンを無効化する際に基礎となる許可を保持するには、トグルを無効にします。デバイスのリンクが解除されると、関連付けられたリフレッシュトークンのみが取り消され、許可はそのまま残ります。

Dashboardの使用

Dashboardを使用して、トークンを発行したアプリケーションへのユーザーの承認済みアクセスを取り消すことができます。これにより、リフレッシュトークンが無効になります。これは、トークン自体を取り消すのと機能的に同じです。

  1. [Dashboard]>[User Management(ユーザー管理)]>[Users(ユーザー)]に移動し、ユーザー名をクリックして表示します。

  2. [Authorized Application(認可アプリケーション)]タブを選択します。このページには、ユーザーがアクセスを許可したすべてのアプリケーションが一覧表示されます。

  3. 承認済みアプリケーションへのユーザーのアクセスを取り消して、リフレッシュトークンを無効にするには、[Revoke(取り消し)]をクリックします。

Authentication APIを使用する

リフレッシュトークンを取り消すには、https://{yourDomain}/oauth/revokePOST要求を送信します。

/oauth/revokeエンドポイントは、特定のトークンだけでなく、許可全体を取り消します。リフレッシュトークンを取り消すには、/api/v2/device-credentialsエンドポイントを使用します。APIは最初にアプリケーションの資格情報を検証し、次にトークンが取り消し要求を行ったアプリケーションに発行されたかどうかを確認します。この検証が失敗すると、要求は拒否され、アプリケーションにエラーが通知されます。次に、APIはトークンを無効にします。無効化は直ちに行われ、取り消し後はトークンを再び使用することはできません。取り消し要求ごとに、同じ承認許可に対して発行されたすべてのトークンが無効になります。


curl --request POST \
  --url 'https://{yourDomain}/oauth/revoke' \
  --header 'content-type: application/json' \
  --data '{ "client_id": "{yourClientId}", "client_secret": "{yourClientSecret}", "token": "{yourRefreshToken}" }'

Was this helpful?

/
var client = new RestClient("https://{yourDomain}/oauth/revoke");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/json");
request.AddParameter("application/json", "{ \"client_id\": \"{yourClientId}\", \"client_secret\": \"{yourClientSecret}\", \"token\": \"{yourRefreshToken}\" }", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);

Was this helpful?

/
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io/ioutil"
)

func main() {

	url := "https://{yourDomain}/oauth/revoke"

	payload := strings.NewReader("{ \"client_id\": \"{yourClientId}\", \"client_secret\": \"{yourClientSecret}\", \"token\": \"{yourRefreshToken}\" }")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("content-type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := ioutil.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}

Was this helpful?

/
HttpResponse<String> response = Unirest.post("https://{yourDomain}/oauth/revoke")
  .header("content-type", "application/json")
  .body("{ \"client_id\": \"{yourClientId}\", \"client_secret\": \"{yourClientSecret}\", \"token\": \"{yourRefreshToken}\" }")
  .asString();

Was this helpful?

/
var axios = require("axios").default;

var options = {
  method: 'POST',
  url: 'https://{yourDomain}/oauth/revoke',
  headers: {'content-type': 'application/json'},
  data: {
    client_id: '{yourClientId}',
    client_secret: '{yourClientSecret}',
    token: '{yourRefreshToken}'
  }
};

axios.request(options).then(function (response) {
  console.log(response.data);
}).catch(function (error) {
  console.error(error);
});

Was this helpful?

/
#import <Foundation/Foundation.h>

NSDictionary *headers = @{ @"content-type": @"application/json" };
NSDictionary *parameters = @{ @"client_id": @"{yourClientId}",
                              @"client_secret": @"{yourClientSecret}",
                              @"token": @"{yourRefreshToken}" };

NSData *postData = [NSJSONSerialization dataWithJSONObject:parameters options:0 error:nil];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://{yourDomain}/oauth/revoke"]
                                                       cachePolicy:NSURLRequestUseProtocolCachePolicy
                                                   timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
                                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
                                                if (error) {
                                                    NSLog(@"%@", error);
                                                } else {
                                                    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
                                                    NSLog(@"%@", httpResponse);
                                                }
                                            }];
[dataTask resume];

Was this helpful?

/
$curl = curl_init();

curl_setopt_array($curl, [
  CURLOPT_URL => "https://{yourDomain}/oauth/revoke",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{ \"client_id\": \"{yourClientId}\", \"client_secret\": \"{yourClientSecret}\", \"token\": \"{yourRefreshToken}\" }",
  CURLOPT_HTTPHEADER => [
    "content-type: application/json"
  ],
]);

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}

Was this helpful?

/
import http.client

conn = http.client.HTTPSConnection("")

payload = "{ \"client_id\": \"{yourClientId}\", \"client_secret\": \"{yourClientSecret}\", \"token\": \"{yourRefreshToken}\" }"

headers = { 'content-type': "application/json" }

conn.request("POST", "/{yourDomain}/oauth/revoke", payload, headers)

res = conn.getresponse()
data = res.read()

print(data.decode("utf-8"))

Was this helpful?

/
require 'uri'
require 'net/http'
require 'openssl'

url = URI("https://{yourDomain}/oauth/revoke")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE

request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/json'
request.body = "{ \"client_id\": \"{yourClientId}\", \"client_secret\": \"{yourClientSecret}\", \"token\": \"{yourRefreshToken}\" }"

response = http.request(request)
puts response.read_body

Was this helpful?

/
import Foundation

let headers = ["content-type": "application/json"]
let parameters = [
  "client_id": "{yourClientId}",
  "client_secret": "{yourClientSecret}",
  "token": "{yourRefreshToken}"
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://{yourDomain}/oauth/revoke")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()

Was this helpful?

/

ここでは、

属性 説明
client_id
必須
アプリケーションのクライアントID。アプリケーションは、リフレッシュトークンが発行されたものと一致する必要があります。
client_secret アプリケーションのクライアントシークレット。機密アプリケーションに必要です。
token
必須
取り消したいリフレッシュトークン。

アプリケーションは、リフレッシュトークンが発行されたものと一致する必要があります。

クライアントシークレットなしでトークンを取り消す

クライアントシークレットを安全に保管できないアプリケーション(ネイティブアプリなど)の場合、/oauth/revokeエンドポイントはクライアントシークレットなしでのアクセスをサポートします。ただし、アプリケーション自体のtokenEndpointAuthMethodプロパティがnoneに設定されている必要があります。tokenEndpointAuthMethod値は、[Dashboard] > [Applications(アプリケーション)] > [Applications(アプリケーション)]から、またはManagement APIを使用して変更できます。

要求が有効な場合、リフレッシュトークンは取り消され、応答はHTTP 200で、応答本文は空です。それ以外の場合、応答本文にはエラーコードと説明が含まれます。

{
      "error": "invalid_request|invalid_client",
      "error_description": "Description of the error"
    }

Was this helpful?

/

考えられる応答は次のとおりです。

HTTPステータス 説明
200 リフレッシュトークンが取り消された、存在しない、または取り消し要求を行うアプリケーションに対して発行されていません。応答本文は空欄のままです。
400 必要なパラメーターが要求で送信されませんでした("error":"invalid_request")。
401 要求は承認されていません("error": "invalid_client")。アプリケーションの資格情報(client_idclient_secret)が要求に存在し、有効な値が指定されていることを確認します。

Management APIの使用

Auth0 Management APIを使用してリフレッシュトークンを取り消すには、取り消すリフレッシュトークンのidが必要です。既存のリフレッシュトークンのリストを取得するには、/api/v2/device-credentialsエンドポイントを呼び出し、type=refresh_tokenuser_idを指定して、read:device_credentialsスコープを含むアクセス トークンを使用します。結果を絞り込むには、トークンに関連付けられたclient_id(わかっている場合)を指定することもできます。

GET https://{yourDomain}/api/v2/device-credentials?
      type=refresh_token
      &client_id=
      &user_id=
    
    {
      "Authorization":   "Bearer {your_access_token}"
    }

Was this helpful?

/

応答本文:

[
      {
    "id": "dcr_dFJiaAxbEroQ5xxx",
    "device_name": "my-device" // the value of 'device' provided in the /authorize call when creating the token
      }
    ]

Was this helpful?

/

リフレッシュトークンを取り消すには、delete:device_credentialsスコープを含むアクセス トークンと上記で取得した ID の値を使用して、/api/v2/device-credentialsエンドポイントを呼び出します。

DELETE https://{yourDomain}/api/v2/device-credentials/{id}
    
    {
      "Authorization":   "Bearer {your_access_token}"
    }

Was this helpful?

/

応答はHTTP 204: The credential no longer exists(認証情報はもう存在しません)になります。

考慮事項と制限

デバイス認可フローでは、デバイスに再認証を強制する唯一の方法は、デバイスに割り当てられたリフレッシュトークンを取り消すことです。詳細については、ユーザーからデバイスのリンクを解除するを参照してください。デバイスは、現在有効なアクセストークンの期限が切れて、アプリケーションが失効したリフレッシュトークンを使おうとするまでは、再認証が強制されないことに注意してください。

リフレッシュトークンのローテーション使用中に以前無効になったトークンが使用されている場合は、その無効になったトークンが発行された以降に発行されたリフレッシュトークンの全セットが付与と同様に直ちに失効され、ユーザーの再認証が必要になります。

  • リフレッシュトークンを取り消すには、Authentication APIの/oauth/revokeエンドポイントを使用します。このエンドポイントは、基礎となる許可を削除しません。この動作を変更して、Dashboardで基礎となる許可も削除できます。[Dashboard] > [Tenant Settings(テナント設定)] > [Advanced(詳細)]Settings(設定)までスクロールし、リフレッシュトークンの取り消しによる許可の削除のトグルを有効にします。

  • ローテーション用に構成されたリフレッシュトークンを取り消すには、Management API/api/v2/device-credentialsエンドポイントを使用します。

もっと詳しく