Chrome Device Token API 範例
透過集合功能整理內容
你可以依據偏好儲存及分類內容。
Python
import jwt
import json
import requests
import sys
import time
import codecs
SERVICE_ACCOUNT_FILE = './service_account_key.json'
JWT_AUDIENCE = 'https://oauth2.googleapis.com/token'
JWT_SCOPE = 'https://www.googleapis.com/auth/chromeosdevicetoken'
TOKEN_REQUEST_URL = 'https://oauth2.googleapis.com/token'
INVALIDATE_TOKEN_API_URL = 'https://chromedevicetoken.googleapis.com/v1/users:invalidateToken'
def get_access_token_for_user(service_account_email, private_key_id, private_key, user_email):
'''
See instructions for getting a signed JWT here
https://developers.google.com/identity/protocols/oauth2/service-account#jwt-auth
'''
iat = time.time()
exp = iat + 3600
payload = {'iss': service_account_email,
'sub': user_email,
'aud': JWT_AUDIENCE,
'scope': JWT_SCOPE,
'iat': iat,
'exp': exp
}
additional_headers = {'kid': private_key_id}
signed_jwt = jwt.encode(payload, private_key, headers=additional_headers,
algorithm='RS256')
grant_type = codecs.decode(
'urn:ietf:params:oauth:grant-type:jwt-bearer', 'unicode_escape')
payload = 'grant_type=' + str(grant_type) + '&assertion=' + signed_jwt
headers = {'Content-Type': 'application/x-www-form-urlencoded'}
response = requests.post(TOKEN_REQUEST_URL, data=payload, headers=headers)
print(f'Response HTTP status code: {response.status_code}')
print(json.dumps(response.json(), indent=2))
return response.json()['access_token']
def invalidate_token(user_email):
print(f'invalidate token for user {user_email}')
with open(SERVICE_ACCOUNT_FILE, 'r') as service_account_key_json_file:
service_account_key = json.load(service_account_key_json_file)
service_account_email = service_account_key['client_email']
private_key_id = service_account_key['private_key_id']
private_key = service_account_key['private_key']
print(f'using service account {service_account_email}')
print(f'using private key id {private_key_id}')
access_token = get_access_token_for_user(service_account_email, private_key_id,
private_key, user_email)
response = requests.post(
INVALIDATE_TOKEN_API_URL,
headers={
'Authorization': 'Bearer ' + access_token,
'Content-Type': 'application/json'
},
json={
'token_type': 'SAML_PASSWORD'
})
# Successful call should have HTTP status code 200 and an empty response body.
print(f'Response HTTP status code: {response.status_code}')
print(json.dumps(response.json(), indent=2))
if __name__ == '__main__':
invalidate_token(sys.argv[1])
C#
private async Task<string> InvalidatePasswordTokenForUser(string userAccessToken)
{
const string tokenRequestURI = "https://chromedevicetoken.googleapis.com/v1/users:invalidateToken";
var jsSerializer = new JavaScriptSerializer();
var body = new Dictionary<string, object>();
body["token_type"] = "SAML_PASSWORD";
string jsonString = jsSerializer.Serialize(body);
HttpWebRequest tokenRequest = (HttpWebRequest)WebRequest.Create(tokenRequestURI);
tokenRequest.Method = "POST";
tokenRequest.Headers.Add(string.Format("Authorization: Bearer {0}", userAccessToken));
tokenRequest.ContentType = "application/json";
tokenRequest.Accept = "Accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8";
byte[] _byteVersion = Encoding.ASCII.GetBytes(jsonString);
tokenRequest.ContentLength = _byteVersion.Length;
Stream stream = tokenRequest.GetRequestStream();
await stream.WriteAsync(_byteVersion, 0, _byteVersion.Length);
stream.Close();
WebResponse tokenResponse = await tokenRequest.GetResponseAsync();
using (StreamReader reader = new StreamReader(tokenResponse.GetResponseStream()))
{
string responseText = await reader.ReadToEndAsync();
if (responseText != null && responseText.Length > 0)
{
return responseText;
}
throw new FormatException("Unexpected response format: " + responseText);
}
}
AppScript
function runInvalidateToken() {
var url = 'https://chromedevicetoken.googleapis.com/v1/users:invalidateToken';
var userToImpersonate = '...@....';
var service = getOAuth2Service(userToImpersonate, 'https://www.googleapis.com/auth/chromeosdevicetoken');
if (service.hasAccess()) {
var param = {
method: 'post',
contentType: 'application/json',
headers: {
Authorization: 'Bearer ' + service.getAccessToken()
},
payload : JSON.stringify({
token_type : 'SAML_PASSWORD'
}),
muteHttpExceptions: true
};
var req = UrlFetchApp.getRequest(url, param);
Logger.log('Request : ');
Logger.log(req);
var response = UrlFetchApp.fetch(url, param);
Logger.log('ResponseCode : ' + response.getResponseCode());
Logger.log('ResponseBody : ' + response.getContentText());
} else {
Logger.log(service.getLastError());
}
}
/*
* This sample demonstrates how to configure the library for Google APIs, using
* domain-wide delegation (Service Account flow).
* https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority
*/
// Private key and client email of the service account.
var PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----\n....\n-----END PRIVATE KEY-----\n';
var CLIENT_EMAIL = '....iam.gserviceaccount.com';
/**
* Reset the authorization state, so that it can be re-tested.
*/
function reset() {
getService().reset();
}
/**
* Configures the service.
*/
function getOAuth2Service(user, scopes) {
return OAuth2.createService('ChromeDeviceTokens:' + user)
// Set the endpoint URL.
.setTokenUrl('https://oauth2.googleapis.com/token')
// Set the private key and issuer.
.setPrivateKey(PRIVATE_KEY)
.setIssuer(CLIENT_EMAIL)
// Set the name of the user to impersonate. This will only work for
// Google Apps for Work/EDU accounts whose admin has setup domain-wide
// delegation:
// https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority
.setSubject(user)
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getScriptProperties())
// Set the scope. This must match one of the scopes configured during the
// setup of domain-wide delegation.
.setScope(scopes);
}
除非另有註明,否則本頁面中的內容是採用創用 CC 姓名標示 4.0 授權,程式碼範例則為阿帕契 2.0 授權。詳情請參閱《Google Developers 網站政策》。Java 是 Oracle 和/或其關聯企業的註冊商標。
上次更新時間:2025-07-25 (世界標準時間)。
[[["容易理解","easyToUnderstand","thumb-up"],["確實解決了我的問題","solvedMyProblem","thumb-up"],["其他","otherUp","thumb-up"]],[["缺少我需要的資訊","missingTheInformationINeed","thumb-down"],["過於複雜/步驟過多","tooComplicatedTooManySteps","thumb-down"],["過時","outOfDate","thumb-down"],["翻譯問題","translationIssue","thumb-down"],["示例/程式碼問題","samplesCodeIssue","thumb-down"],["其他","otherDown","thumb-down"]],["上次更新時間:2025-07-25 (世界標準時間)。"],[[["\u003cp\u003eThe code samples demonstrate how to invalidate a user's SAML password token for Chrome OS devices using the Chrome Device Token API.\u003c/p\u003e\n"],["\u003cp\u003eIt showcases implementations in Python, C#, and Appscript, each leveraging a service account for authentication.\u003c/p\u003e\n"],["\u003cp\u003eThe process involves obtaining an access token using the service account and then making a request to the \u003ccode\u003eusers:invalidateToken\u003c/code\u003e API endpoint.\u003c/p\u003e\n"],["\u003cp\u003eThe service account needs to be granted the \u003ccode\u003ehttps://www.googleapis.com/auth/chromeosdevicetoken\u003c/code\u003e scope and domain-wide delegation should be configured for Appscript.\u003c/p\u003e\n"]]],[],null,["# Chrome Device Token API Samples\n\n### Python\n\n import jwt\n import json\n import requests\n import sys\n import time\n import codecs\n\n SERVICE_ACCOUNT_FILE = './service_account_key.json'\n\n JWT_AUDIENCE = 'https://oauth2.googleapis.com/token'\n JWT_SCOPE = 'https://www.googleapis.com/auth/chromeosdevicetoken'\n TOKEN_REQUEST_URL = 'https://oauth2.googleapis.com/token'\n INVALIDATE_TOKEN_API_URL = 'https://chromedevicetoken.googleapis.com/v1/users:invalidateToken'\n\n def get_access_token_for_user(service_account_email, private_key_id, private_key, user_email):\n '''\n See instructions for getting a signed JWT here\n https://developers.google.com/identity/protocols/oauth2/service-account#jwt-auth\n '''\n iat = time.time()\n exp = iat + 3600\n payload = {'iss': service_account_email,\n 'sub': user_email,\n 'aud': JWT_AUDIENCE,\n 'scope': JWT_SCOPE,\n 'iat': iat,\n 'exp': exp\n }\n additional_headers = {'kid': private_key_id}\n signed_jwt = jwt.encode(payload, private_key, headers=additional_headers,\n algorithm='RS256')\n\n grant_type = codecs.decode(\n 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'unicode_escape')\n payload = 'grant_type=' + str(grant_type) + '&assertion=' + signed_jwt\n headers = {'Content-Type': 'application/x-www-form-urlencoded'}\n\n response = requests.post(TOKEN_REQUEST_URL, data=payload, headers=headers)\n\n print(f'Response HTTP status code: {response.status_code}')\n print(json.dumps(response.json(), indent=2))\n\n return response.json()['access_token']\n\n def invalidate_token(user_email):\n print(f'invalidate token for user {user_email}')\n\n with open(SERVICE_ACCOUNT_FILE, 'r') as service_account_key_json_file:\n service_account_key = json.load(service_account_key_json_file)\n\n service_account_email = service_account_key['client_email']\n private_key_id = service_account_key['private_key_id']\n private_key = service_account_key['private_key']\n print(f'using service account {service_account_email}')\n print(f'using private key id {private_key_id}')\n\n access_token = get_access_token_for_user(service_account_email, private_key_id,\n private_key, user_email)\n\n response = requests.post(\n INVALIDATE_TOKEN_API_URL,\n headers={\n 'Authorization': 'Bearer ' + access_token,\n 'Content-Type': 'application/json'\n },\n json={\n 'token_type': 'SAML_PASSWORD'\n })\n\n # Successful call should have HTTP status code 200 and an empty response body.\n print(f'Response HTTP status code: {response.status_code}')\n print(json.dumps(response.json(), indent=2))\n\n if __name__ == '__main__':\n invalidate_token(sys.argv[1])\n\n### C#\n\n private async Task\u003cstring\u003e InvalidatePasswordTokenForUser(string userAccessToken)\n {\n const string tokenRequestURI = \"https://chromedevicetoken.googleapis.com/v1/users:invalidateToken\";\n\n var jsSerializer = new JavaScriptSerializer();\n var body = new Dictionary\u003cstring, object\u003e();\n body[\"token_type\"] = \"SAML_PASSWORD\";\n string jsonString = jsSerializer.Serialize(body);\n\n HttpWebRequest tokenRequest = (HttpWebRequest)WebRequest.Create(tokenRequestURI);\n tokenRequest.Method = \"POST\";\n tokenRequest.Headers.Add(string.Format(\"Authorization: Bearer {0}\", userAccessToken));\n tokenRequest.ContentType = \"application/json\";\n tokenRequest.Accept = \"Accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\";\n byte[] _byteVersion = Encoding.ASCII.GetBytes(jsonString);\n tokenRequest.ContentLength = _byteVersion.Length;\n Stream stream = tokenRequest.GetRequestStream();\n await stream.WriteAsync(_byteVersion, 0, _byteVersion.Length);\n stream.Close();\n\n WebResponse tokenResponse = await tokenRequest.GetResponseAsync();\n using (StreamReader reader = new StreamReader(tokenResponse.GetResponseStream()))\n {\n string responseText = await reader.ReadToEndAsync();\n\n if (responseText != null && responseText.Length \u003e 0)\n {\n return responseText;\n }\n throw new FormatException(\"Unexpected response format: \" + responseText);\n }\n }\n\n### Appscript\n\n function runInvalidateToken() {\n var url = 'https://chromedevicetoken.googleapis.com/v1/users:invalidateToken';\n var userToImpersonate = '...@....';\n var service = getOAuth2Service(userToImpersonate, 'https://www.googleapis.com/auth/chromeosdevicetoken');\n\n if (service.hasAccess()) {\n var param = {\n method: 'post',\n contentType: 'application/json',\n headers: {\n Authorization: 'Bearer ' + service.getAccessToken()\n },\n payload : JSON.stringify({\n token_type : 'SAML_PASSWORD'\n }),\n muteHttpExceptions: true\n };\n\n var req = UrlFetchApp.getRequest(url, param);\n Logger.log('Request : ');\n Logger.log(req);\n\n var response = UrlFetchApp.fetch(url, param);\n Logger.log('ResponseCode : ' + response.getResponseCode());\n Logger.log('ResponseBody : ' + response.getContentText());\n } else {\n Logger.log(service.getLastError());\n }\n }\n\n /*\n * This sample demonstrates how to configure the library for Google APIs, using\n * domain-wide delegation (Service Account flow).\n * https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority\n */\n\n // Private key and client email of the service account.\n var PRIVATE_KEY = '-----BEGIN PRIVATE KEY-----\\n....\\n-----END PRIVATE KEY-----\\n';\n var CLIENT_EMAIL = '....iam.gserviceaccount.com';\n\n /**\n * Reset the authorization state, so that it can be re-tested.\n */\n function reset() {\n getService().reset();\n }\n\n /**\n * Configures the service.\n */\n function getOAuth2Service(user, scopes) {\n return OAuth2.createService('ChromeDeviceTokens:' + user)\n // Set the endpoint URL.\n .setTokenUrl('https://oauth2.googleapis.com/token')\n\n // Set the private key and issuer.\n .setPrivateKey(PRIVATE_KEY)\n .setIssuer(CLIENT_EMAIL)\n\n // Set the name of the user to impersonate. This will only work for\n // Google Apps for Work/EDU accounts whose admin has setup domain-wide\n // delegation:\n // https://developers.google.com/identity/protocols/OAuth2ServiceAccount#delegatingauthority\n .setSubject(user)\n\n // Set the property store where authorized tokens should be persisted.\n .setPropertyStore(PropertiesService.getScriptProperties())\n\n // Set the scope. This must match one of the scopes configured during the\n // setup of domain-wide delegation.\n .setScope(scopes);\n }"]]