[PHP] Zoom APIを利用してミーティングを作成するで、Zoom APIを利用してミーティングを作成する方法が詳しく記載されていますが、lcobucci/jwtの4系ではZoom API用のJWTトークンの作成方法が変わっています。
4系でのトークン作成について簡単に説明します。
TL;DR
lcobucci/jwt4系は、デフォルトのClaimFormatterが日付系をマイクロ秒ありUnixタイムスタンプにフォーマットするので、Zoom APIが401を返してくる。日付をマイクロ秒なしUNIXタイムスタンプにフォーマットしてトークン作成することで正常にZoom APIにアクセスできる。
lobucci/jwtインストール
composer require lobucci/jwt
トークン作成
Configurationインスタンスを作る
3系ではBuilderを使ってトークン作成していましたが、4系ではまずConfigurationインスタンスを作成します。
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
$apiSecret = '[ZOOM API SECRET]';
$configuration = Configuration::forSymmetricSigner(
new Sha256(), // 暗号化ハッシュ関数
InMemory::plainText($apiSecret) // キー
);
Zoomは、HMAC SHA256を利用しているので、ハッシュ関数には Lcobucci\JWT\Signer\Hmac\Sha256
を、キーはZoom API管理画面から平文で取得できるのでLcobucci\JWT\Signer\Key\InMemory::plainText()
でセットします。
Builderからトークン作成、そして失敗
トークン作成用のBuilderは$configuration->builder()
で取得できるので、これを利用します。
※このコードでは動作しません!!!
$apiKey = '[ZOOM API KEY]';
$now = new \DateTimeImmutable();
$token = $configuration->builder()
->issuedBy($apiKey)
->issuedAt($now)
->expiresAt($now->modify('+1 hour'))
->getToken($configuration->signer(), $configuration->signingKey());
作成日時や有効期限といった日付系はUNIXタイムからDateTimeImmutable
型に変更になっています。
Builderのそれぞれのメソッドに渡す値につぃては以下の通りです。
メソッド名 | 引数 |
---|---|
issuedBy | APIキー |
issuedAt | トークン作成日 |
expiredAt | 有効期限 |
値をセットして、getToken($configuration->signer(), $configuration->signingKey())
でトークンを作成しますが、このトークンではZoom APIにアクセスしても401 Unauthorizedが返ってきます。
作成したトークンでAPIにアクセスできない原因は日付系フォーマット
4系のBuilderで生成されたトークンのClaim部分とZoom APIの管理画面から生成した値を比べてみました。
{
"aud": null,
"iss": "APIキー",
"exp": 1610972172,
"iat": 1610966772
}
{
"iss": "APIキー",
"iat": "1611019091.181495",
"exp": "1611022691.181495"
}
4系では、日付系のフォーマットにマイクロ秒が付随しているのに対し、Zoom管理画面から生成したものにはマイクロ秒が付随していません。(audはなくても問題なし)
lcobucci/jwtのコードを追ってみると...
public static function default(): self
{
return new self(new UnifyAudience(), new MicrosecondBasedDateConversion()); // <- ここ
}
private function convertDate(DateTimeImmutable $date)
{
$seconds = $date->format('U');
$microseconds = $date->format('u');
if ((int) $microseconds === 0) {
return (int) $seconds;
}
return $seconds . '.' . $microseconds; // <- ここ
}
というようになっています。lcobucci/jwtではLcobucci\JWT\ClaimsFormatte
インターフェイスを実装したフォーマッタークラスがあり、これを利用してClaimをフォーマットしていますが、デフォルトでは日付はマイクロ秒つきのUnixタイムスタンプになるフォーマッターが使われてしまいます。これが原因でした。
日付をマイクロ秒なしUNIXタイムスタンプにフォーマットしてトークン作成する
マイクロ秒なしUNIXタイムスタンプ用のフォーマッターを作る
まず、マイクロ秒なしにするためには独自のフォーマッターを作ります。
<?php
use Lcobucci\JWT\ClaimsFormatter;
use Lcobucci\JWT\Token\RegisteredClaims;
class UnixTimestampFormatter implements ClaimsFormatter
{
/** @inheritdoc */
public function formatClaims(array $claims): array
{
foreach (RegisteredClaims::DATE_CLAIMS as $claim) {
if (! array_key_exists($claim, $claims)) {
continue;
}
assert($claims[$claim] instanceof \DateTimeImmutable);
$claims[$claim] = $claims[$claim]->getTimestamp();
}
return $claims;
}
}
独自フォーマッターを使ってトークンを作成する
作成したフォーマッターは$configuration->builder()
に引数で渡せます。独自フォーマッターを渡せば、あとは前述の通りでZoom APIにアクセスすることができるトークンを作成できます。Configurationインスタンス作成を含めた、一連のコードは以下の通りです。
use Lcobucci\JWT\Configuration;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key\InMemory;
use UnixTimestampFormatter;
$apiKey = '[ZOOM API KEY]';
$apiSecret = '[ZOOM API SECRET]';
$now = new \DateTimeImmutable();
// Configurationインスタンス作成
$configuration = Configuration::forSymmetricSigner(
new Sha256(), // 暗号化ハッシュ関数
InMemory::plainText($apiSecret) // キー
);
// トークン作成
$token = $configuration->builder(new UnixTimestampFormatter())
->issuedBy($apiKey)
->issuedAt($now)
->expiresAt($now->modify('+1 hour'))
->getToken($configuration->signer(), $configuration->signingKey());
トークン作成後は、[PHP] Zoom APIを利用してミーティングを作成すると同様です。