0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Javaを用いたJWT生成ロジック実装

Last updated at Posted at 2025-05-31

概要

認証の勉強がてらJavaを用いてJWTの生成ロジックを組んでみたので備忘録として残します。

各種バージョン等

ライブラリ名 グループID / アーティファクトID 使用バージョン
Spring Boot org.springframework.boot:spring-boot-starter-parent 3.4.5
Java java.version (プロパティ) 17
JWT (JJWT) io.jsonwebtoken:jjwt 0.12.6
BouncyCastle (JCAプロバイダ) org.bouncycastle:bcprov-jdk18on 1.78

秘密鍵の生成

JWTの署名部分を生成する際に用いる秘密鍵を生成します。
適当なディレクトリ上で以下コマンドを実行し、RSA256アルゴリズムを用いてPEM形式の秘密鍵を生成します。

openssl genrsa 2048 > RS256_private.pem

RS256_private.pemが生成されます。中身を確認すると以下のようなPEM形式の秘密鍵が確認できます。

-----BEGIN RSA PRIVATE KEY-----
###########################
-----END PUBLIC KEY-----

公開鍵(検証用)の抽出

同ディレクトリ上で以下コマンドを実行し、先ほど生成した秘密鍵から公開鍵を抽出します。

openssl rsa -in RS256_private.pem -pubout > RS256_public.pem

RS256_public.pemが生成されます。中身を確認すると以下のようなPEM形式の公開鍵が確認できます。

-----BEGIN PUBLIC KEY-----
###########################
-----END PUBLIC KEY-----

秘密鍵を環境変数にセット

秘密鍵は秘匿情報のため、ハードコーディングは避けるようにしましょう。今回は環境変数に格納したものをJavaのコードから取得します。

JWT_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----
###########################
-----END RSA PRIVATE KEY-----"

Javaコードから秘密鍵を取得

環境変数から秘密鍵を取得し、PrivateKeyオブジェクトを生成して返すPrivateKeyGetterを実装します。


@Component
public class PrivateKeyGetter {
    public PrivateKey getPrivateKey()
    {
        final String pem = System.getenv("JWT_PRIVATE_KEY");

        if (pem == null || pem.isEmpty()) {
            throw new IllegalArgumentException("JWT_PRIVATE_KEYの値が存在しません。");
        }

        if (!pem.startsWith("-----BEGIN RSA PRIVATE KEY-----") || !pem.endsWith("-----END RSA PRIVATE KEY-----")) {
            throw new IllegalArgumentException("JWT_PRIVATE_KEYの値が不正です。");
        }

        try {       
            // PEMデータを読み込む
            PemReader pemReader = new PemReader(new StringReader(pem));
            PemObject pemObject = pemReader.readPemObject();
            pemReader.close();
            
            if (pemObject == null || !pemObject.getType().equals("RSA PRIVATE KEY")) {
                throw new IllegalArgumentException("PEMオブジェクトがRSA秘密鍵ではありません");
            }

            byte[] keyBytes = pemObject.getContent();

            RSAPrivateKey rsaPrivateKey = RSAPrivateKey.getInstance(keyBytes);

            RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(
                rsaPrivateKey.getModulus(),
                rsaPrivateKey.getPrivateExponent()
            );

            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return keyFactory.generatePrivate(keySpec);
        }
        catch(IOException e) {
            throw new RuntimeException(e.getMessage());
        }
        catch(NoSuchAlgorithmException e) {
            throw new RuntimeException(e.getMessage());
        }
        catch(InvalidKeySpecException e) {
            throw new RuntimeException(e.getMessage());
        }
    }
}

JWT生成ロジック

JWTの生成を担うJwtGeneratorを実装します。subjectprofile、そして発行日有効期限などの各種クレーム情報をセットします。そして、先ほど実装したPrivateKeyGetterを用いてJWTにRSA署名を付与します。これにより、JWTの内容改竄を防ぎます。


@Component
public class JwtGenerator {
    private final PrivateKeyGetter privateKeyGetter;

    public InternalAuthIdTokenGenerator(PrivateKeyGetter privateKeyGetter) {
        this.privateKeyGetter = privateKeyGetter;
    }

    public String generate(
        final String subject,
        final String email,
        final Map<String, String> profile
    ) {
        Instant now = Instant.now();

        PrivateKey privateKey = privateKeyGetter.getPrivateKey();

        return Jwts.builder()
            .subject(subject)
            .claim("profile", profile)
            .issuedAt(Date.from(now))
            .expiration(Date.from(now.plus(7, ChronoUnit.DAYS)))
            .signWith(privateKey, Jwts.SIG.RS256)
            .compact();
    }
}

JWT用エンドポイントの実装

Spring MVCを用いて、JWTをレスポンスとして返却するコントローラーを実装します。

@RestController
@RequestMapping(path = "/api")
public class GetJwtController {
    private final JwtGenerator jwtGenerator;

    public GetJwtController(JwtGenerator jwtGenerator) {
        this.jwtGenerator = jwtGenerator;
    }

    @GetMapping("/auth/token")
    public ResponseEntity<?> getJwt(@RequestBody PasswordAuthRequest request) {
        Map<String, String> profile = new HashMap<>();
        profile.put("email", "tanaka@example.com");
        profile.put("name", "田中太郎");
        profile.put("image_url", "https://example.com/hoge.png");
        String jwt = jwtGenerator.generate("68b26f50-e046-31dd-5cc4-2109f7c64e74", profile);
        return ResponseEntity.ok(jwt);
    }
}

実行結果

Postman等のAPIクライアントを用いて/api/auth/tokenにリクエストを投げます。JWTトークンが返却されることを確認できます。

eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI2OGIyNmY1MC1lMDQ2LTMxZGQtNWNjNC0yMTA5ZjdjNjRlNzQiLCJwcm9maWxlIjp7ImltYWdlX3VybCI6Imh0dHBzOi8vZXhhbXBsZS5jb20vaG9nZS5wbmciLCJuYW1lIjoi55Sw5Lit5aSq6YOOIiwiZW1haWwiOiJ0YW5ha2FAZXhhbXBsZS5jb20ifSwiaWF0IjoxNzQ4NzAxODI1LCJleHAiOjE3NDkzMDY2MjV9.aIngltR0cq2feolJwiVeuFu5OXcFl26wr-JlojFY5ziXoEF6ka-ZedTbWpNM7vs0vZB8wa07-4E6ELfpsjKZyyum9veBnEvplU12KsHX7mexIo7Rknn5XTdVnAxUGHyziFgsUWrPb7TOXIH2rSkAI_rvSt7HlVkSn-bk-anuQg3z39NW9LKIu4_xdX_cU7q2iY0fzmISf-2tzGUwZtYKS02yhV4-FH8ol2t_zMbZ46pAOk7Z3swl1LJ4AyM7iVylqJNmaI_IfC2MbAGsLHDxkveTibrIN7HIOTEqvgi7R_ySjVkctZbri1Vp-O81SwZ01suPGRLOQP5Q5NGIcEbSLw

JWTの内容確認

以下サイトにアクセスし、JWTを確認します。JWT欄に先ほどの実行結果を貼り付けると右側にヘッダーとペイロードの値が表示されます。ペイロードには、JwtGeneratorに渡した値が含まれていることが確認できます。
また、パブリックキー欄にRS256_public.pemの中身を貼り付けることで署名検証に成功することも確認可能です。

jwt.png

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?