RustでAuth0のJWKSを介さずJWTを検証する

はじめに

セキュリティ的に検証できているわけではないので鵜呑みにはしないでください。

インターネットに繋げない

いま開発中のアプリケーションでは IDaaS に Auth0 を利用しているのですが、 バックエンドサーバーがインターネットに接続できないので JWKS にアクセスができません。

そのため代替案として各 Applications から取得できる公開鍵を使ってjwks.jsonにアクセスせずに JWT をデコードしてみました。

公開鍵の取得

JWT の公開鍵を取得する必要があります。

https://auth0.com/docs/secure/tokens/json-web-tokens/validate-json-web-tokens#verify-rs256-signed-tokens

取得方法は ↑ の「3.」までの通りです。

具体的な実装

以上を踏まえて実装はこんな感じです。

pub struct Claim {
    pub sub: String,
    pub exp: usize,
}

pub fn decode_token(token: &str) -> Result<Claim, std::error::Error> {
    let public_key = std::env::var("PUBLIC_KEY")
        .replace("CERTIFICATE", "PUBLIC KEY")
        .as_bytes();

    let key = &jsonwebtoken::DecodingKey::from_rsa_pem(public_key).unwrap();
    let header = jsonwebtoken::decode_header(token)?;
    let validation = &jsonwebtoken::Validation::new(header.alg);

    let result = jsonwebtoken::decode::<Claim>(token, key, validation)?;

    Ok(result.claim)
}

JWT のデコードについてはGitHub - Keats/jsonwebtoken: JWT lib in rustを利用しました。

Rust の JWT 関係のライブラリはいくつかありますが、今回はこちらのサンプルから拝借しました。

環境変数のPUBLIC_KEYには公開鍵を

AUTH0_PUBLIC_KEY=-----BEGIN CERTIFICATE-----\...\n...\...\n-----END CERTIFICATE-----

といったように一行で設定する必要があります。

公開鍵のreplaceについてはこちらの issueのおかげで解決できました。 というかこれは罠では……?

……と、いろいろ紆余曲折ありながらなんとか実装はできました。

しかし、キーのローテーションが実行されてしまうと公開鍵が使い物にならなくなってしまうので、特殊な事情がない限りはjwks.jsonを参照することをおすすめします。