技術系TIPS
PR

【Java版】CognitoのIDトークンのJWT検証とダミートークンの作成

saratogax
記事内に商品プロモーションを含む場合があります

前回、AWS SDK を使って Cognito 認証を実現しました。

あわせて読みたい
【Java版】AWSのSDKを使ってCognito認証を実現する
【Java版】AWSのSDKを使ってCognito認証を実現する

その際、取得した ID トークンについて JWT 形式の文字列を検証してみようということになりました。

今回は、この JWT の文字列の中身の確認とダミートークンの作成について紹介していきます。

JWT形式について

JWT は JSON Web Token(ウェブトークン)の略で、ドット区切りの文字列で構成されています。

・ヘッダ
・ペイロード
・署名

ドットでセパレートされたそれぞれの文字列は Base64 エンコードされているので、デコードすることで中身の確認ができます。

AWS でも以下のドキュメントが用意されているので、署名も含めて検証される場合は参考にしてください。

ID トークンの署名は、JWT トークンのヘッダーとペイロードに基づいて計算されます。Web API のアプリケーション外で使用するときは、常にこの署名を検証してからトークンを受け入れる必要があります。

JSON web トークンの検証

アプリケーションの認証方法として Amazon Cognito ユーザープールを使用したいと考えています。クライアントからアプリケーションに送信された ID とアクセストークンを検証する安全な方法は何ですか?

ウェブトークンの署名を復号して検証する方法

ヘッダ部の確認

参考までに、ヘッダ部を見てみましょう。

$ echo 'xxxxxxxxxx' | base64 -D | jq .

parse error: Unfinished string at EOF at line 1, column 69

おっと、JSON 文字列の最後のカッコが抜けているようですね。

{“kid”: “xxxxxxxxxxxxxxxxxxxx”,”alg”: “RS256”

Base64 エンコードされているものの、どうやらパディング部分が省略されているので必要に応じて「=」を追加してみると良さそうです。

$ echo 'xxxxxxxxxx==' | base64 -D | jq .

結果、以下の JSON が確認できると思います。

{
  "kid": "xxxxxxxxxxxxxxxxxxxx",
  "alg": "RS256"
}

「alg」はトークンの署名に使用されるアルゴリズムで、RS256 は SHA-256 を持つ RSA 署名のこと。

ペイロード部の確認

ペイロード部にはトークンの有効期限や所有者(ユーザ)に関連する情報があります。

{
  "sub": "xxxxxxxxxx",
  "aud": "xxxxxxxxxx",
  "event_id": "xxxxxxxxxx",
  "token_use": "id",
  "auth_time": 1646060400,
  "iss": "https://cognito-idp.[リージョン].amazonaws.com/[ユーザープールID]",
  "cognito:username": "xxxxxxxxxx",
  "custom:client_id": "xxxxxxxxxx",
  "exp": 1646060400,
  "iat": 1646060400,
  "email": "xxxxxxxxxx"
}

この中でチェックしておくと良い項目は以下の 4 つです。

・aud(対象者)
・token_use
・iss(Issuer)
・exp(有効期限)

ダミートークンの作成

ダミートークンはライブラリを使うと簡単にできますが、アルゴリズムによって署名の部分がややこしいです。

HMAC256 だと楽なのですが、RS256 は少し面倒かな・・・。

今回は java-jwt のライブラリを利用してみます。

Gradle で利用する場合は以下の通り。

implementation("com.auth0:java-jwt:3.18.3")

HMAC256

HMAC256 は任意の文字列で Algorithm オブジェクトが生成できるのでそのまま使えます。

Algorithm algorithm = Algorithm.HMAC256("secret");

return JWT.create()
    .withAudience("xxxxxxxxxx")
    .withIssuer("https://cognito-idp.[リージョン].amazonaws.com/[ユーザープールID]")
    .withClaim("token_use", "id")
    .withExpiresAt(new Date())
    .sign(algorithm);

RS256

無理やりダミーの署名を用意しましょうか。

KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");
keygen.initialize(1024);
KeyPair keyPair = keygen.generateKeyPair();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);

return JWT.create()
    .withAudience("xxxxxxxxxx")
    .withIssuer("https://cognito-idp.[リージョン].amazonaws.com/[ユーザープールID]")
    .withClaim("token_use", "id")
    .withExpiresAt(new Date())
    .sign(algorithm);

まとめ

Cognito 認証で取得した ID トークンの JWT の中身を確認してみました。

メインはトークンの有効期限チェックになると思いますが、その他の情報も知っておくといいですね。

また ID トークンに見せかけた、ダミーの JWT の作成にもチャレンジしました。

純粋にトークンを作成したい場合や、テスト用のトークン作成用途として使えそうです。

JWT 形式の文字列は、利用用途が増えてきているので、どのような形式になっているのか理解しておきたいですね。

ABOUT ME
saratoga
saratoga
フリーランスエンジニア
仕事にも趣味にも IT を駆使するフリーランスエンジニア。技術的な TIPS や日々の生活の中で深堀りしてみたくなったことを備忘録として残していきます。
記事URLをコピーしました