認証とアクセストークンの取得
外部システムは、OAuth 2.0のclient_credentialsを使ってmetatellの認証基盤からアクセストークンを取得します。クライアント認証方式は、登録した公開鍵に対応する秘密鍵で署名するprivate_key_jwtです。取得したアクセストークンを外部APIの認証に使用します。
client assertionの仕様
client assertionはES256で署名し、次のヘッダーとクレームを含めます。
JWTヘッダー
| 項目 | 値 |
|---|---|
alg | ES256 |
kid | 管理画面へ登録した公開鍵のkid |
typ | JWT |
JWTクレーム
| クレーム | 値 |
|---|---|
iss / sub | 管理画面に表示されるclient_id |
aud | 管理画面に表示されるtoken endpoint |
jti | リクエストごとに一意な値 |
iat | JWTを作成した時刻 |
exp | client assertionの有効期限。次の例では作成から60秒後 |
Node.jsでトークンを取得する
以下の例ではjoseを使用します。
clientIdとtokenEndpointには、管理画面のクライアント詳細画面に表示されたclient_idとtoken endpointを指定します。
get-access-token.mjsを作成します。
import { randomUUID } from 'node:crypto'
import { importJWK, SignJWT } from 'jose'
const clientId = '<client_id>'
const tokenEndpoint = '<token endpoint>'
const privateJwk = {
kty: 'EC',
crv: 'P-256',
kid: '<kid>',
alg: 'ES256',
use: 'sig',
x: '<x>',
y: '<y>',
d: '<d>'
}
const signingKey = await importJWK(privateJwk, 'ES256')
const assertion = await new SignJWT({})
.setProtectedHeader({ alg: 'ES256', kid: privateJwk.kid, typ: 'JWT' })
.setIssuer(clientId)
.setSubject(clientId)
.setAudience(tokenEndpoint)
.setJti(randomUUID())
.setIssuedAt()
.setExpirationTime('60s')
.sign(signingKey)
const tokenResponse = await fetch(tokenEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: clientId,
client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
client_assertion: assertion
})
})
if (!tokenResponse.ok) {
throw new Error(`アクセストークンの取得に失敗しました: ${tokenResponse.status}`)
}
const { access_token: accessToken, expires_in: expiresIn } = await tokenResponse.json()
以下のコマンドでスクリプトを実行します。
node get-access-token.mjs
取得するアクセストークンの有効期限は5分です。
取得したaccessTokenを、外部APIリクエストのAuthorizationヘッダーへ指定します。
Authorization: Bearer <access-token>
アクセストークンを取得できたら、外部クライアント向けAPIの仕様に従ってロールAPIを呼び出します。