Service Account 認証 (JWT)

Service Account 認証は、JSON Web Token (以降、JWT) を使用してアプリ専用の仮想管理者アカウントで認証を行い、Access Token を発行して API を利用する方法です。
Service Account 認証 (JWT) を使用した Access Token の発行は、以下の流れで行います。

  1. アプリ開発者は、事前に Developer Console で認証アプリを構成する。アプリで必要となる Scope を指定し、Service Account と Private Key を発行する。
  2. アプリは、アプリの Client Id と Service Account を使用して JWT を生成する(RFC-7519)
  3. アプリは、Private Key を使用して JWT をデジタル署名する(RFC-7515)
  4. アプリは、LINE WORKS に Access Token の発行を要求する(RFC-7523)
  5. アプリは、Access Token の有効期限が過ぎた場合、Refresh Token を使用して Access Token の再発行を LINE WORKS に要求する

Access Token / Refresh Token の有効期限 {#token-expiry}

Access Token、Refresh Token には、それぞれ有効期限が設けられています。

  • Access Token

    • 有効期限: 1 時間 または 24 時間
  • Refresh Token

    • 有効期限: 90 日

Service Account について {#service-account}

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 の情報は以下のように表示されます。

  • 姓 : "[SERVICE]"
  • 名 : アプリ名
  • ID : {発行した Service Account}@domain

事前準備 {#preparation}

Developer Console に認証アプリを登録し、以下のアプリ情報を準備します。

  • Client ID
  • Client Secret
  • Service Account
  • Private Key

利用フロー {#jwt-flow}

auth_service_account

JWT の生成 {#generate-jwt}

JWT は以下の形式を使用してください。

{Header BASE64 URL エンコード}.{JSON Claims Set BASE64 URL エンコード}.{signature BASE64 URL エンコード}

以下は実際の JWT の例です。

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJaYnNPcTZ6anQwSWh0WlpucmMiLCJzdWIiOiIxd2FneC5zZXJ2aWNlYWNjb3VudEBleGFtcGxlLmNvbSIsImlhdCI6MTY4Mjg3MTgyNSwiZXhwIjoxNjgyODc1NDI1fQ.aICZ8qvYFKSJT6VdrmEcs6siCHaCgFkqpVs5VALKhf98sZjguppp-bOy9MpNlNepfSF0IyrdG3JavHLUYBz1NEVVZJwEm39f7gODmnt-_kGfDo1YtOqnclP1gM8oiObF2AH2Eneh3XuyeVeZbKAZmp6I_ZOf8AGayVVui61CsDPbUIPZSKUnbW1-vlXboTlojxJhvHznpYSNanHSrg5Nht2VO5sOeclEgPqg3J8Y6XOT60u8Morv5wHUy8a0QyO0yWCT5OJdXeVj94qfDAM15a1Puw9PfQOPm7QhOarvCJ8cOSqo9PHluq9-KZ1WXmfxSo-_itTb8y2YRT3kd21maQ

Header {#jwt-header}

Header に RSA SHA-256 アルゴリズム "RS256" を明示します。

{ "alg": "RS256", "typ": "JWT" }

この値を BASE64 URL エンコードすると以下になります。

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9

JSON Claims Set {#jwt-json-claims-set}

JSON Claims Set は、以下の情報を含む JSON 形式の文字列です。

パラメータ説明
issアプリの Client ID
required
subService Account ID
required
iatJWT 生成日時
UNIX 時間で指定(単位: sec)
required
expJWT 満了日時
最長で 60 分後まで指定可能
UNIX 時間で指定(単位: sec)
required
delegated_userService Account にアクセス権限を委任するユーザー (email)
指定可能な最大数: 1 (固定)

例: 以下の条件の場合

  • Client ID: ZbsOq6zjt0IhtZZnrc
  • Service Account:1wagx.serviceaccount@example.com
  • JWT 生成日時: 2023-05-01 01:23:45
  • JWT 満了日時: 2023-05-01 02:23:45 (60 分後満了)

JSON 形式での表示

{  "iss": "ZbsOq6zjt0IhtZZnrc",  "sub": "1wagx.serviceaccount@example.com",  "iat": 1682871825,  "exp": 1682875425}

この値を BASE64 URL エンコードすると、以下になります。

eyJpc3MiOiJaYnNPcTZ6anQwSWh0WlpucmMiLCJzdWIiOiIxd2FneC5zZXJ2aWNlYWNjb3VudEBleGFtcGxlLmNvbSIsImlhdCI6MTY4Mjg3MTgyNSwiZXhwIjoxNjgyODc1NDI1fQ

JWT デジタル署名 (Signature) {#jwt-signature}

デジタル署名は 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 の場合には以下のライブラリを利用できます。
    • https://github.com/jwtk/jjwt
    • https://github.com/auth0/java-jwt
    • https://bitbucket.org/b_c/jose4j/wiki/Home
    • https://bitbucket.org/connect2id/nimbus-jose-jwt/wiki/Home

JWT における iat/exp の正しい指定について {#jwt-iat-exp-guide}

サービス アカウント (Service Account) のトークンを発行するための JWT を作成する際には、iat (Issued At) と exp (Expiration Time) クレームを正しく設定する必要があります。

条件説明
exp - iat <= 3600exp は 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桁) の値で指定します。

Access Token の発行 {#issue-access-token}

Request URL {#issue-access-token-request-url}

POST https://auth.worksmobile.com/oauth2/v2.0/token

Request Headers {#issue-access-token-request-header}

Content-Type: application/x-www-form-urlencoded

Request Body {#issue-access-token-request-body}

以下の項目を POST で送信する。

パラメータタイプ説明
assertionStringJWT の値
required
grant_typeString"urn:ietf:params:oauth:grant-type:jwt-bearer" (固定)
required
client_idStringアプリの Client ID
required
client_secretStringアプリの Client Secret
required
scopeString利用する Scope
複数の Scope を指定する場合には半角スペースで区切る
required

Request Example {#issue-access-token-request-example}

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'

Response Body (JSON) {#issue-access-token-response-body}

パラメータタイプ説明
access_tokenStringAccess Token
refresh_tokenStringRefresh Token
token_typeString"Bearer" (固定)
expires_inStringAccess Token の有効期限
有効期限は、Developer Console > API > ClientApp の [トークン設定 > Access Tokenの有効期限] の設定に従う。
・1 hour (3600 秒)
・24 hours (86400 秒)
設定された有効期限が経過すると、自動的に満了する。
scopeStringAccess Token で利用できる Scope

Response Example{#issue-access-token-response-example}

{  "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 を再発行できます。

Access Token の再発行 {#refresh-access-token}

User Account 認証 (OAuth) > Access Token の再発行 を参照してください。

Token の無効化 {#revoke-token}

User Account 認証 (OAuth) > Token の無効化 を参照してください。

Access Token の使用 {#how-to-use-access-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 {#prohibited-api}

認証アプリでは、Service Account はユーザーによる認証を行うこと無く、API を通して、ユーザーの持つ一部のデータにアクセスすることができます。

重要なユーザー情報を取り扱う API など、一部の API は、Service Account 認証で発行された Access Token では呼び出すことができません。
Service Account 認証では利用できない API は以下のとおりです。

ScopesAPIs
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*

アクセス委任アプリ {#delegated}

アクセス委任アプリでは、ユーザーのアクセス権限を Service Account に委任し、Service Account が Service Account では利用できない API を呼び出してユーザーがサービス上で個別に所有しているデータにアクセスすることができます。
アクセス委任アプリは、最高管理者が、以下の手順で作成します。

  1. Developer Console で API > ClientApp へアクセスし、アプリの新規追加 をクリックします。
  2. アプリ名を入力します。
  3. 認証アプリ の横の 「?」 をクリックし、作成する をクリックします。
  4. 注意事項を確認し、チェックボックスをチェックした後に、同意して利用する をクリックします。

アクセス委任を行うには、JSON Claims Set の delegated_user に、委任の対象となるユーザーを指定し、Access Token を発行します。取得した Access Token を利用すると、ユーザーがサービス上で個別に所有しているデータにアクセスできます。