クライアントクレデンシャルフローによるトークンの取得
このページでは、デジタル認証アプリサービス API を使用するための最初のステップとして、アクセストークンを取得する方法を説明します。
トークンの取得には、OpenID Connect のクライアントクレデンシャルフロー(クライアントアプリケーションが自身の資格情報を使用してアクセストークンを取得する認証方式)を使用します。
シーケンス
実装例
- Go
package main
import (
"bytes"
"fmt"
"io"
"net/http"
"net/url"
"time"
"github.com/go-jose/go-jose/v4"
"github.com/go-jose/go-jose/v4/jwt"
)
const (
// デジタル庁から発行されたクライアント ID です。ご自身のクライアント ID で置き換えてください。
clientID = "<YOUR_CLIENT_ID>"
// クライアント認証用の秘密鍵(JWK 形式)です。ご自身の秘密鍵で置き換えてください。
clientPrivateKey = "<YOUR_SECRET_JWK>"
// デジタル認証アプリサービスのトークンエンドポイント URL
tokenURL = "https://sb-auth-and-sign.go.jp/api/realms/main/protocol/openid-connect/token"
)
// クライアント認証に使用するクライアントアサーション(JWT)を作成します
func generateClientAssertion(clientID, clientPrivateKey, tokenURL string) (string, error) {
var jwk jose.JSONWebKey
if err := jwk.UnmarshalJSON([]byte(clientPrivateKey)); err != nil {
return "", fmt.Errorf("failed to parse JWK: %w", err)
}
signer, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.SignatureAlgorithm(jwk.Algorithm), Key: jwk}, nil)
if err != nil {
return "", fmt.Errorf("failed to create signer: %w", err)
}
now := time.Now()
token, err := jwt.Signed(signer).Claims(jwt.Claims{
Issuer: clientID,
Subject: clientID,
Audience: jwt.Audience{tokenURL},
IssuedAt: jwt.NewNumericDate(now),
Expiry: jwt.NewNumericDate(now.Add(5 * time.Second)),
ID: fmt.Sprintf("%s_%d", clientID, now.UnixNano()),
}).Serialize()
if err != nil {
return "", fmt.Errorf("failed to sign token: %w", err)
}
return token, nil
}
func run() error {
// クライアント認証用のアサーションを生成します。
clientAssertion, err := generateClientAssertion(clientID, clientPrivateKey, tokenURL)
if err != nil {
return fmt.Errorf("failed to generate client assertion: %w", err)
}
// OAuth 2.0 トークンリクエストのパラメータを設定
reqBody := url.Values{}
// クライアントクレデンシャルフローでは grant_type に "client_credentials" を指定
reqBody.Set("grant_type", "client_credentials")
reqBody.Set("client_id", clientID)
reqBody.Set("client_assertion_type", "urn:ietf:params:oauth:client-assertion-type:jwt-bearer")
reqBody.Set("client_assertion", clientAssertion)
// 署名 API を使用するためのスコープを指定
reqBody.Set("scope", "sign")
// トークンエンドポイントにリクエストを送信します。
resp, err := http.Post(tokenURL, "application/x-www-form-urlencoded", bytes.NewBufferString(reqBody.Encode()))
if err != nil {
return fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()
// レスポンスを読み込みます。
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %w", err)
}
fmt.Println(string(respBody))
return nil
}
func main() {
if err := run(); err != nil {
panic(err)
}
}
実行結果
アクセストークンの取得に成功すると、以下のようなレスポンスが返されます:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhVFN4RHpxM1B6c2dhak0wN3YzWmxGSm8tajBWUGdaVWQ1d0NPOUJydkx3In0...",
"expires_in": 900,
"refresh_expires_in": 0,
"token_type": "Bearer",
"not_before_policy": 0,
"scope": "openid offline_access sign"
}
次のステップ
アクセストークンを取得できたら、署名トランザクションの開始を行いましょう。
その他、デジタル認証アプリサービス API の使い方やエラーの詳細等については、デジタル認証アプリのマニュアルをご覧ください。