3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Kotlinでjwks-rsa-javaを使ったJWKの取得方法

Posted at

JWKとは

JSON Web Keyとは暗号鍵を表現するためのJSONデータ構造のことで、ID Tokenの検証などに用いられる。
また複数のJWKのセットのことをJWKS(JWK Set)と呼ぶ。

jwks-rsa-javaライブラリを使ってみる

公式のGitHubを参考に基本的な機能を作成してみます。

まずはGradleを使ってライブラリを取得しましょう。
またjava-jwtライブラリも使用するので入れておきます。

gradle.build
implementation 'com.auth0:jwks-rsa:0.8.2'
implementation 'com.auth0:java-jwt:3.8.1'

JWTからkey idの取得

公式のリポジトリにあるサンプル用のJWTからkey id(kid)を取得しましょう。

サンプル用JWT
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlJrSTVNakk1T1VZNU9EYzFOMFE0UXpNME9VWXpOa1ZHTVRKRE9VRXpRa0ZDT1RVM05qRTJSZyJ9.eyJpc3MiOiJodHRwczovL3NhbmRyaW5vLmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHw1NjMyNTAxZjQ2OGYwZjE3NTZmNGNhYjAiLCJhdWQiOiJQN2JhQnRTc3JmQlhPY3A5bHlsMUZEZVh0ZmFKUzRyViIsImV4cCI6MTQ2ODk2NDkyNiwiaWF0IjoxNDY4OTI4OTI2fQ.NaNeRSDCNu522u4hcVhV65plQOiGPStgSzVW4vR0liZYQBlZ_3OKqCmHXsu28NwVHW7_KfVgOz4m3BK6eMDZk50dAKf9LQzHhiG8acZLzm5bNMU3iobSAJdRhweRht544ZJkzJ-scS1fyI4gaPS5aD3SaLRYWR0Xsb6N1HU86trnbn-XSYSspNqzIUeJjduEpPwC53V8E2r1WZXbqEHwM9_BGEeNTQ8X9NqCUvbQtnylgYR3mfJRL14JsCWNFmmamgNNHAI0uAJo84mu_03I25eVuCK0VYStLPd0XFEyMVFpk48Bg9KNWLMZ7OUGTB_uv_1u19wKYtqeTbt9m1YcPMQ

こちらの記事を参考にJWTをデコードし、kidを取得します。

val token: String = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IlJrSTVNakk1T1VZNU9EYzFOMFE0UXpNME9VWXpOa1ZHTVRKRE9VRXpRa0ZDT1RVM05qRTJSZyJ9.eyJpc3MiOiJodHRwczovL3NhbmRyaW5vLmF1dGgwLmNvbS8iLCJzdWIiOiJhdXRoMHw1NjMyNTAxZjQ2OGYwZjE3NTZmNGNhYjAiLCJhdWQiOiJQN2JhQnRTc3JmQlhPY3A5bHlsMUZEZVh0ZmFKUzRyViIsImV4cCI6MTQ2ODk2NDkyNiwiaWF0IjoxNDY4OTI4OTI2fQ.NaNeRSDCNu522u4hcVhV65plQOiGPStgSzVW4vR0liZYQBlZ_3OKqCmHXsu28NwVHW7_KfVgOz4m3BK6eMDZk50dAKf9LQzHhiG8acZLzm5bNMU3iobSAJdRhweRht544ZJkzJ-scS1fyI4gaPS5aD3SaLRYWR0Xsb6N1HU86trnbn-XSYSspNqzIUeJjduEpPwC53V8E2r1WZXbqEHwM9_BGEeNTQ8X9NqCUvbQtnylgYR3mfJRL14JsCWNFmmamgNNHAI0uAJo84mu_03I25eVuCK0VYStLPd0XFEyMVFpk48Bg9KNWLMZ7OUGTB_uv_1u19wKYtqeTbt9m1YcPMQ"

val jwt = JWT.decode(token)

val keyId: String = jwt.getKeyId()
// keyId = RkI5MjI5OUY5ODc1N0Q4QzM0OUYzNkVGMTJDOUEzQkFCOTU3NjE2Rg

issuerからjwksの取得

UrlJwkProviderを使って指定されたURLからjwksを取得します。

val issuer: String = jwt.getIssuer()
// issuer = https://samples.auth0.com/

val issuer_path= ".well-known/jwks.json"
// こちらはリポジトリに記載されている。本来はドメイン提供者から指定されるもの。

val provider = UrlJwkProvider(URL(issuer + issuer_path))
// https://samples.auth0.com/jwks.well-known/jwks.jsonからjwksを取得する。
// 今回の場合はjwksのなかにjwkは一つしかない。

val jwk = provider.get(keyId)
// 取得したjwksの中からkidがkeyIdと同一のjwkを取得する。

jwksをキャッシュとして保持する

今のままだとユーザからリクエストがあるたびにjwksを取得し直す事になってしまい、そのまま放置しておくと認証サーバからアクセス過多で弾かれかねません。
そこでGuavaCachedJwkProviderjwksを使ってjwksをキャッシュに保持しましょう。

val http = UrlJwkProvider(URL(issuer + issuer_path))
val provider = GuavaCachedJwkProvider(http)

val jwk = provider.get(keyId)

キャッシュに保持しているjwks内にkeyIdと一致するkidが存在しない場合、UrlJwkProviderへとjwksを取得しにいきます。

デフォルトでは5個のキーを10時間保持しますが、この設定を変えることも可能です。

パブリックキーの生成とtokenの検証

jwkを取得できたのでパブリックキーを生成してみましょう。
jwkの中を見てみると、どうやらe値とn値しかないようなのでそれを使います。

val publicKey: RSAPublicKey = jwk.publicKey as RSAPublicKey

たったこれだけでパブリックキーを取得できます。
ちなみに中ではこんなことをやっています。

KeyFactory kf = KeyFactory.getInstance(PUBLIC_KEY_ALGORITHM);
BigInteger modulus = new BigInteger(1, Base64.decodeBase64(stringValue("n")));
BigInteger exponent = new BigInteger(1, Base64.decodeBase64(stringValue("e")));
return kf.generatePublic(new RSAPublicKeySpec(modulus, exponent));

では早速tokenを検証してみましょう。
ちなみにサンプルのJWTはtokenの期限が2016年となっているので、検証が成功することはありません。

val algorithm = Algorithm.RSA256(publicKey,null) // 署名の検証なので公開鍵のみ(非推奨)

val verifier = JWT.require(algorithm)
            .withIssuer("https://samples.auth0.com/")
            .build()

val result = verifier.verify(token)

参考文献

auth0/jwks-rsa-java
JSON Web Key (JWK)
auth0/java-jwt
Kotlinでjava-jwtを使ってTokenを見てみる

3
3
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
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?