JWTを作ってみる

JWSを作ってみたので、JWTも作ってみようと。

使用するライブラリは以前と同じです。

https://connect2id.com/products/nimbus-jose-jwt

作り方はこちらに載っていました。

https://connect2id.com/products/nimbus-jose-jwt/examples/jwt-with-hmac

実際に書いてみたコードはこちら。

import com.nimbusds.jose.JOSEException;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;

import java.security.SecureRandom;
import java.text.ParseException;
import java.util.Date;

public class JWT_HS256 {
    public static void main(String[] args) throws JOSEException, ParseException {
        SecureRandom secureRandom = new SecureRandom();
        byte[] sharedSecret = new byte[32];
        secureRandom.nextBytes(sharedSecret);

        // HMACの署名を行うクラスの作成
        MACSigner signer = new MACSigner(sharedSecret);

        // JWTクレーム・セットの作成
        JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
                .subject("alice")
                .issuer("https://fogefoge.com")
                .expirationTime(new Date(new Date().getTime() + 60 * 1000))
                .build();

        // JWSヘッダーとJWTクレームセットを合わせ、署名を行い、JWTを作成
        SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claimsSet);
        signedJWT.sign(signer);

        String s = signedJWT.serialize();
        System.out.println("Created jwt: " + s);

        // JWTをデシリアライズ
        SignedJWT parsedSignedJWT = SignedJWT.parse(s);

        // JWTの署名を検証
        JWSVerifier verifier = new MACVerifier(sharedSecret);
        System.out.println("Verify mac: " + parsedSignedJWT.verify(verifier));

        // JWTのクレームを取得
        System.out.println(parsedSignedJWT.getJWTClaimsSet().getSubject());
        System.out.println(parsedSignedJWT.getJWTClaimsSet().getIssuer());
        System.out.println(parsedSignedJWT.getJWTClaimsSet().getExpirationTime());
    }
}

JWSとJWTのRFCを軽く読んだだけですが、各メソッドやクラスが正しくRFCの内容と一致しているかなと思います。JWSヘッダーがあり、クレームセットがあって、JWTが作られるあたりとか特に。

ちなみにJWTを署名処理しないでシリアライズしようとすると例外が出て怒られます。

        SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claimsSet);
        System.out.println("Before sign jwt: " + signedJWT.serialize());
Exception in thread "main" java.lang.IllegalStateException: The JWS object must be in a signed or verified state
    at com.nimbusds.jose.JWSObject.ensureSignedOrVerifiedState(JWSObject.java:264)
    at com.nimbusds.jose.JWSObject.serialize(JWSObject.java:420)
    at com.nimbusds.jose.JWSObject.serialize(JWSObject.java:399)
    at JWT_HS256.main(JWT_HS256.java:32)