Service Account 認証は、JSON Web Token (以降、JWT) を使用してアプリ専用の仮想管理者アカウントで認証を行い、Access Token を発行して API を利用する方法です。
Service Account 認証 (JWT) を使用した Access Token の発行は、以下の流れで行います。
Access Token、Refresh Token には、それぞれ有効期限が設けられています。
Access Token
Refresh Token
LINE WORKS API を利用するにはユーザーまたは Service Account による認証を行う必要があります。
Service Account とは、ユーザーによる認証を行わずに LINE WORKS API を利用するために用意された仮想的なアカウントで、以下の特徴があります。
1 つのアプリに対し 1 つの Service Account のみ発行できます
発行と同時に管理者権限が付与され、管理者にサービス通知されます
発行元のアプリ以外では使用できません
アプリ専用の仮想管理者アカウントであるため課金の対象になりません
利用できない API があります
Path パラメータの {userId} に対して、me を使用できません
組織連携や BOT によるメッセージ送信などのアプリでは、Service Account を利用して、ユーザーによる認証を行わないアプリを構成できます。 Service Account は、Developer Console のアプリ設定で発行します。
発行した Service Account の情報は以下のように表示されます。
Developer Console に認証アプリを登録し、以下のアプリ情報を準備します。
JWT は以下の形式を使用してください。
{Header BASE64 URL エンコード}.{JSON Claims Set BASE64 URL エンコード}.{signature BASE64 URL エンコード}以下は実際の JWT の例です。
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJaYnNPcTZ6anQwSWh0WlpucmMiLCJzdWIiOiIxd2FneC5zZXJ2aWNlYWNjb3VudEBleGFtcGxlLmNvbSIsImlhdCI6MTY4Mjg3MTgyNSwiZXhwIjoxNjgyODc1NDI1fQ.aICZ8qvYFKSJT6VdrmEcs6siCHaCgFkqpVs5VALKhf98sZjguppp-bOy9MpNlNepfSF0IyrdG3JavHLUYBz1NEVVZJwEm39f7gODmnt-_kGfDo1YtOqnclP1gM8oiObF2AH2Eneh3XuyeVeZbKAZmp6I_ZOf8AGayVVui61CsDPbUIPZSKUnbW1-vlXboTlojxJhvHznpYSNanHSrg5Nht2VO5sOeclEgPqg3J8Y6XOT60u8Morv5wHUy8a0QyO0yWCT5OJdXeVj94qfDAM15a1Puw9PfQOPm7QhOarvCJ8cOSqo9PHluq9-KZ1WXmfxSo-_itTb8y2YRT3kd21maQHeader に RSA SHA-256 アルゴリズム "RS256" を明示します。
{ "alg": "RS256", "typ": "JWT" }この値を BASE64 URL エンコードすると以下になります。
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9JSON Claims Set は、以下の情報を含む JSON 形式の文字列です。
| パラメータ | 説明 |
|---|---|
| iss | アプリの Client ID required |
| sub | Service Account ID required |
| iat | JWT 生成日時 UNIX 時間で指定(単位: sec) required |
| exp | JWT 満了日時 最長で 60 分後まで指定可能 UNIX 時間で指定(単位: sec) required |
| delegated_user | Service Account にアクセス権限を委任するユーザー (email) 指定可能な最大数: 1 (固定) |
例: 以下の条件の場合
JSON 形式での表示
{ "iss": "ZbsOq6zjt0IhtZZnrc", "sub": "1wagx.serviceaccount@example.com", "iat": 1682871825, "exp": 1682875425}この値を BASE64 URL エンコードすると、以下になります。
eyJpc3MiOiJaYnNPcTZ6anQwSWh0WlpucmMiLCJzdWIiOiIxd2FneC5zZXJ2aWNlYWNjb3VudEBleGFtcGxlLmNvbSIsImlhdCI6MTY4Mjg3MTgyNSwiZXhwIjoxNjgyODc1NDI1fQデジタル署名は JWS (JSON Web Signature RFC-7515) 規約に従い、先に生成した JWT header と body の byte array を、Developer Console でダウンロードした Private Key を用いて RSA SHA-256 アルゴリズム (Header で定めた "RS256") で署名し、BASE64 URL エンコードします。
Header と Claims Set を "." で組み合わせると {header BASE64 URL エンコード}.{JSON Claims Set BASE64 URL エンコード} は以下になります。
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJaYnNPcTZ6anQwSWh0WlpucmMiLCJzdWIiOiIxd2FneC5zZXJ2aWNlYWNjb3VudEBleGFtcGxlLmNvbSIsImlhdCI6MTY4Mjg3MTgyNSwiZXhwIjoxNjgyODc1NDI1fQ生成した {Header BASE64 URL エンコード}.{JSON Claims Set BASE64 URL エンコード} をデジタル署名して、BASE64 URL エンコードすると {Signature BASE64 URL エンコード} は以下になります。
RqOaErJWZc_ZGijL5r0a892NnQL_zbkgchThW3j4pzG_qMqtOgex2odEs8JFsPfQ2c8_2BkaUMckNIN3C27t2RsbppJYl3nQr9w2Jb6x9LJR1Ym3pJVlpRvarracRwa00OgVc0mZ5dkn3B4I55GpKjZ3oOLfW7Xw0OAj8fEYCmWJmma3xQQrScJAUqN-jTZ7T3C6-ieVo3IhTRopzS5cru3ilQWekQ6-fRTPr8W4EV9B0u8wXhCxT90mlAYtebPvyovpPTNhi8Oq8rO_gVnpSMNkDtZ6p6OpC7_XG7ZcjUo7KRCxyPLe2-TmeWtV0jL5vqsjnlAznKtw5mPGOwpjVQ最終的に完成した JWT {Header BASE64 URL エンコード}.{JSON Claims Set BASE64 URL エンコード}.{Signature BASE64 URL エンコード} は以下になります。
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJaYnNPcTZ6anQwSWh0WlpucmMiLCJzdWIiOiIxd2FneC5zZXJ2aWNlYWNjb3VudEBleGFtcGxlLmNvbSIsImlhdCI6MTY4Mjg3MTgyNSwiZXhwIjoxNjgyODc1NDI1fQ.RqOaErJWZc_ZGijL5r0a892NnQL_zbkgchThW3j4pzG_qMqtOgex2odEs8JFsPfQ2c8_2BkaUMckNIN3C27t2RsbppJYl3nQr9w2Jb6x9LJR1Ym3pJVlpRvarracRwa00OgVc0mZ5dkn3B4I55GpKjZ3oOLfW7Xw0OAj8fEYCmWJmma3xQQrScJAUqN-jTZ7T3C6-ieVo3IhTRopzS5cru3ilQWekQ6-fRTPr8W4EV9B0u8wXhCxT90mlAYtebPvyovpPTNhi8Oq8rO_gVnpSMNkDtZ6p6OpC7_XG7ZcjUo7KRCxyPLe2-TmeWtV0jL5vqsjnlAznKtw5mPGOwpjVQ以降の Token リクエストでは、生成した JWT を assertion パラメータとして渡します。
参考
- JWT の生成には、ライブラリの利用を推奨します。
- 一例として、Java の場合には以下のライブラリを利用できます。
サービス アカウント (Service Account) のトークンを発行するための JWT を作成する際には、iat (Issued At) と exp (Expiration Time) クレームを正しく設定する必要があります。
| 条件 | 説明 |
|---|---|
| exp - iat <= 3600 | exp は iat から 3600秒 (一時間) 以内である必要があります。 |
| now < exp | サーバーでの検証時刻は、exp よりも前である必要があります。 |
| now >= iat | サーバーの検証時刻は、iat 以降である必要があります。 |
よくある失敗の原因と解決策
iat/exp を固定値で指定する
解決策 : トークンの発行を要求するたびに、現在の時刻に基づいて iat/exp を毎回新しく作成する必要があります。
タイムゾーンを元にした時刻を iat/exp に指定する
解決策 : iat/exp に指定する Unix Time は、ローカルタイムゾーンに依存しない、UTC を基準として表します。現在の時刻を Unix Time に変換する際に、ローカルタイムゾーンに基づいた時刻にならないよう注意します。
iat/exp をミリ秒で指定する
解決策 : iat/exp は、1970-01-01T00:00:00Z UTC からの経過時間を秒で表わした数値であることが RFC 7519 で規定されています。ミリ秒 (13桁) ではなく秒 (10桁) の値で指定します。
POST https://auth.worksmobile.com/oauth2/v2.0/tokenContent-Type: application/x-www-form-urlencoded以下の項目を POST で送信する。
| パラメータ | タイプ | 説明 |
|---|---|---|
| assertion | String | JWT の値 required |
| grant_type | String | "urn:ietf:params:oauth:grant-type:jwt-bearer" (固定) required |
| client_id | String | アプリの Client ID required |
| client_secret | String | アプリの Client Secret required |
| scope | String | 利用する Scope 複数の Scope を指定する場合には半角スペースで区切る required |
curl --location --request POST 'https://auth.worksmobile.com/oauth2/v2.0/token' \--header 'Content-Type: application/x-www-form-urlencoded' \--data-urlencode 'assertion=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJaYnNPcTZ6anQwSWh0WlpucmMiLCJzdWIiOiIxd2FneC5zZXJ2aWNlYWNjb3VudEBleGFtcGxlLmNvbSIsImlhdCI6MTY4Mjg3MTgyNSwiZXhwIjoxNjgyODc1NDI1fQ.RqOaErJWZc_ZGijL5r0a892NnQL_zbkgchThW3j4pzG_qMqtOgex2odEs8JFsPfQ2c8_2BkaUMckNIN3C27t2RsbppJYl3nQr9w2Jb6x9LJR1Ym3pJVlpRvarracRwa00OgVc0mZ5dkn3B4I55GpKjZ3oOLfW7Xw0OAj8fEYCmWJmma3xQQrScJAUqN-jTZ7T3C6-ieVo3IhTRopzS5cru3ilQWekQ6-fRTPr8W4EV9B0u8wXhCxT90mlAYtebPvyovpPTNhi8Oq8rO_gVnpSMNkDtZ6p6OpC7_XG7ZcjUo7KRCxyPLe2-TmeWtV0jL5vqsjnlAznKtw5mPGOwpjVQ' \--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer' \--data-urlencode 'client_id=ZbsOq6zjt0IhtZZnrc' \--data-urlencode 'client_secret=oRm3M_nBg6' \--data-urlencode 'scope=bot user.read'| パラメータ | タイプ | 説明 |
|---|---|---|
| access_token | String | Access Token |
| refresh_token | String | Refresh Token |
| token_type | String | "Bearer" (固定) |
| expires_in | String | Access Token の有効期限 有効期限は、Developer Console > API > ClientApp の [トークン設定 > Access Tokenの有効期限] の設定に従う。 ・1 hour (3600 秒) ・24 hours (86400 秒) 設定された有効期限が経過すると、自動的に満了する。 |
| scope | String | Access Token で利用できる Scope |
{ "access_token": "jp1AAABFNKyxc7xsVRQVKrTNFchiiMkQrfJMDM6whobYxfbO4fsF23mvuxRvSuMY57DG4uPI/NI4eNMSt8sroqpqFhe3HemLI3OvCar5FFfOQdqUBgqFA/MaHZVXHqsNJgoX7KaGwDTum+zhEyfwjGSrrJZfSoRpTHHrwny4F4UDEA1Lep3dVUUUKAIQHcq0TwCjiWkMnJAXMEFFfbdVzH3FCv+kpb2OH1NbYzL376fXLh3vMUlyRBXPTf3Lv0bK5NsvjR3BNMR3GSvVzjM59lR5ctBK8PvtTdmaHbVGXzJBHv+S3mp1UuD0szSuxCsWUrdCS7/PiWbQwM4++k+WM/bta5EB9v9s9YQGlyklE3fqhnYLGx/9jWanFgrvptCambOW8lv5A==", "refresh_token": "jp1AAAAVq8kTeVPKkD11iLMP1mTqzYOd2T/r2x6QoBM2P3D8X6FfDi9wG5Hepsmh/LVpo3n3d/jcP/rnhtEw1VOpU4MJnxHVzu1x5VhKRmG/o63HERu2bnMtFHQVsjhljcf5fpm+Q==", "scope": "bot user.read", "token_type": "Bearer", "expires_in": "86400"}Service Account を利用した JWT 認証に失敗するとエラーを返します。エラー内容はレスポンスボディで確認できます。
注意
- Token と共に、Access Token の有効期限と Refresh Token を保存することを推奨します。
- API の利用時に Access Token の有効期限を確認し、有効期限が終了している場合には Refresh Token を用いて Access Token を再発行できます。
User Account 認証 (OAuth) > Access Token の再発行 を参照してください。
User Account 認証 (OAuth) > Token の無効化 を参照してください。
発行された Access Tokenは、認証スキーム Bearer と組み合わせて Authorization HTTP Request Header に指定し、API を呼び出します。
注意
- Authorization タイプに Bearer を明示し、Bearer と Token を 1 つの半角スペースでつなぎます。
PostMethod method = new PostMethod(url);method.setRequestHeader("Authorization", "Bearer AAAA5IdUiCj5emZowcf49VRu7qbb548g6aGE");認証アプリでは、Service Account はユーザーによる認証を行うこと無く、API を通して、ユーザーの持つ一部のデータにアクセスすることができます。
重要なユーザー情報を取り扱う API など、一部の API は、Service Account 認証で発行された Access Token では呼び出すことができません。
Service Account 認証では利用できない API は以下のとおりです。
| Scopes | APIs |
|---|---|
| group.note group.note.read | /groups/{groupId}/note* |
| mail mail.read | /users/{userId}/mail* ただし、以下の API は利用可能 • /users/{userId}/mail/migration* • /users/{userId}/mail/settings/forwarding |
| file file.read | /users/{userId}/drive* /sharedrives* |
| file file.read group.folder group.folder.read | /groups/{groupId}/folder* |
| task task.read | /tasks* /users/{userId}/tasks* /users/{userId}/task-categories* |
| form form.read | /forms* |
| ainote ainote.read | /users/{userId}/ainote* |
アクセス委任アプリでは、ユーザーのアクセス権限を Service Account に委任し、Service Account が Service Account では利用できない API を呼び出してユーザーがサービス上で個別に所有しているデータにアクセスすることができます。
アクセス委任アプリは、最高管理者が、以下の手順で作成します。
アクセス委任を行うには、JSON Claims Set の delegated_user に、委任の対象となるユーザーを指定し、Access Token を発行します。取得した Access Token を利用すると、ユーザーがサービス上で個別に所有しているデータにアクセスできます。