メインコンテンツまでスキップ

認証とアクセストークンの取得

外部システムは、OAuth 2.0のclient_credentialsを使ってmetatellの認証基盤からアクセストークンを取得します。クライアント認証方式は、登録した公開鍵に対応する秘密鍵で署名するprivate_key_jwtです。取得したアクセストークンを外部APIの認証に使用します。

client assertionの仕様

client assertionはES256で署名し、次のヘッダーとクレームを含めます。

JWTヘッダー

項目
algES256
kid管理画面へ登録した公開鍵のkid
typJWT

JWTクレーム

クレーム
iss / sub管理画面に表示されるclient_id
aud管理画面に表示されるtoken endpoint
jtiリクエストごとに一意な値
iatJWTを作成した時刻
expclient assertionの有効期限。次の例では作成から60秒後

Node.jsでトークンを取得する

以下の例ではjoseを使用します。

clientIdtokenEndpointには、管理画面のクライアント詳細画面に表示されたclient_idtoken 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を呼び出します。