3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LINE WORKSAdvent Calendar 2024

Day 9

LINE WORKS Service Account 認証 (JWT) の確認ポイント (RFC に準拠しましょう)

Last updated at Posted at 2024-12-09

LINE WORKS Service Account 認証 (JWT) の確認ポイント

LINE WORKS API の Service Account 認証のエラーで悩んだら、JWT (JSON Web Token) の RFC 準拠を確認してみましょう。RFC 非準拠によるエラーの可能性があります。

LINE WORKS API を利用する際の Service Account 認証では、JWT を用いてトークン生成を行います。JWT の取り扱いにおいては、RFC-7519 (JWT)、RFC-7515 (JWS)、および RFC-7523 (JWT Profile for OAuth 2.0) に準拠する必要があります。これにより、標準に沿ったトークン生成が可能となり、LINE WORKS API の認証が正しく行われます。

確認したいポイント

1. Base64 エンコード

JWT のヘッダーとペイロード部分は、「Base64 URL エンコード」でエンコードする必要がありますが、一般的な Base64 エンコードを用いるケースが見受けられます。

RFC-7515 (JSON Web Signature) の該当箇所

Base64url Encoding
...
No padding (e.g., using "=") characters are used in base64url-encoded data.

例えば、Google Apps Script (GAS) を使用する場合、Utilities.base64EncodeWebSafe を利用します。これは、URL セーフな Base64 エンコードを行い、+-/_ に置き換え、さらに不要なパディング文字である = を削除 します。

もし Utilities.base64Encode を使用すると、URL セーフではない形式でエンコードするため、JWT の仕様に準拠しません。

  • RFC 準拠:
var encodedHeader = Utilities.base64EncodeWebSafe(JSON.stringify(header));
var encodedPayload = Utilities.base64EncodeWebSafe(JSON.stringify(payload));
  • 非準拠:
var encodedHeader = Utilities.base64Encode(JSON.stringify(header));
var encodedPayload = Utilities.base64Encode(JSON.stringify(payload));

2. Claim Set (exp, iat) の型

exp (有効期限) や iat (発行時刻) は、UNIX タイムスタンプとして数値型で記述する必要があります。しかし、これを文字列型で指定してしまう例があります。

誤りの例

{
  "exp": "1672531200",
  "iat": "1672527600"
}

正しい方法

{
  "exp": 1672531200,
  "iat": 1672527600
}

RFC-7519 (JSON Web Token) の該当箇所

The "exp" (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing. The value MUST be a number representing seconds since the epoch.
The "iat" (issued at) claim identifies the time at which the JWT was issued. The value MUST be a number representing seconds since the epoch.

JWT の生成方法例

以下に、Python と Google Apps Script を使用した正しい JWT 生成の例を示します。

Python の例

import jwt
import time

# JWT ヘッダー
header = {
    "alg": "RS256",
    "typ": "JWT"
}

# JWT ペイロード
payload = {
    "iss": "your_client_id",
    "sub": "your_service_account",
    "iat": int(time.time()),  # 発行時刻
    "exp": int(time.time()) + 3600  # 有効期限
}

# 秘密鍵
private_key = """-----BEGIN PRIVATE KEY-----
your_private_key
-----END PRIVATE KEY-----"""

# JWT 生成
token = jwt.encode(payload, private_key, algorithm="RS256", headers=header)

print("Generated JWT:")
print(token)

Google Apps Script の例

function createJWT() {
  var header = {
    "alg": "RS256",
    "typ": "JWT"
  };

  var payload = {
    "iss": "your_client_id",
    "sub": "your_service_account",
    "iat": Math.floor(Date.now() / 1000),  // 発行時刻 (数値型)
    "exp": Math.floor(Date.now() / 1000) + 3600  // 有効期限 (数値型)
  };

  var encodedHeader = Utilities.base64EncodeWebSafe(JSON.stringify(header));
  var encodedPayload = Utilities.base64EncodeWebSafe(JSON.stringify(payload));

  var signature = Utilities.computeRsaSha256Signature(encodedHeader + "." + encodedPayload, privateKey);
  var encodedSignature = Utilities.base64EncodeWebSafe(signature);

  return encodedHeader + "." + encodedPayload + "." + encodedSignature;
}

まとめ

JWT を正しく生成するためには、以下のポイントを守ることが重要です。

  1. Base64 URL エンコードを使用
    一般的な Base64 エンコードではなく、URL セーフな形式を使用する。

  2. Claim Set (exp, iat) を数値型で指定
    RFC に準拠するため、UNIX タイムスタンプを使用する。

これらの実装ミスを避けることで、LINE WORKS との認証連携を円滑に行うことができます。

参考

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?