1*e7b1675dSTing-Kang Chang /** 2*e7b1675dSTing-Kang Chang * Copyright 2021 Google LLC 3*e7b1675dSTing-Kang Chang * 4*e7b1675dSTing-Kang Chang * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5*e7b1675dSTing-Kang Chang * in compliance with the License. You may obtain a copy of the License at 6*e7b1675dSTing-Kang Chang * 7*e7b1675dSTing-Kang Chang * http://www.apache.org/licenses/LICENSE-2.0 8*e7b1675dSTing-Kang Chang * 9*e7b1675dSTing-Kang Chang * Unless required by applicable law or agreed to in writing, software distributed under the License 10*e7b1675dSTing-Kang Chang * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11*e7b1675dSTing-Kang Chang * or implied. See the License for the specific language governing permissions and limitations under 12*e7b1675dSTing-Kang Chang * the License. 13*e7b1675dSTing-Kang Chang */ 14*e7b1675dSTing-Kang Chang // [START java-jwt-verify-example] 15*e7b1675dSTing-Kang Chang package jwt; 16*e7b1675dSTing-Kang Chang 17*e7b1675dSTing-Kang Chang import static java.nio.charset.StandardCharsets.UTF_8; 18*e7b1675dSTing-Kang Chang 19*e7b1675dSTing-Kang Chang import com.google.crypto.tink.KeysetHandle; 20*e7b1675dSTing-Kang Chang import com.google.crypto.tink.jwt.JwkSetConverter; 21*e7b1675dSTing-Kang Chang import com.google.crypto.tink.jwt.JwtPublicKeyVerify; 22*e7b1675dSTing-Kang Chang import com.google.crypto.tink.jwt.JwtSignatureConfig; 23*e7b1675dSTing-Kang Chang import com.google.crypto.tink.jwt.JwtValidator; 24*e7b1675dSTing-Kang Chang import com.google.crypto.tink.jwt.VerifiedJwt; 25*e7b1675dSTing-Kang Chang import java.nio.file.Files; 26*e7b1675dSTing-Kang Chang import java.nio.file.Path; 27*e7b1675dSTing-Kang Chang import java.nio.file.Paths; 28*e7b1675dSTing-Kang Chang import java.time.Instant; 29*e7b1675dSTing-Kang Chang import java.time.temporal.ChronoUnit; 30*e7b1675dSTing-Kang Chang import java.util.List; 31*e7b1675dSTing-Kang Chang 32*e7b1675dSTing-Kang Chang /** 33*e7b1675dSTing-Kang Chang * A command-line utility for verifying JSON Web Tokens (JWTs). 34*e7b1675dSTing-Kang Chang * 35*e7b1675dSTing-Kang Chang * <p>It requires the following arguments: 36*e7b1675dSTing-Kang Chang * 37*e7b1675dSTing-Kang Chang * <ul> 38*e7b1675dSTing-Kang Chang * <li>public-jwkset-file: Name of the input file containing the public keyset in JWK set format. 39*e7b1675dSTing-Kang Chang * <li>audience: The audience claim to be used in the token 40*e7b1675dSTing-Kang Chang * <li>token-file: name of the input file containing the signed JWT. 41*e7b1675dSTing-Kang Chang */ 42*e7b1675dSTing-Kang Chang public final class JwtVerify { main(String[] args)43*e7b1675dSTing-Kang Chang public static void main(String[] args) throws Exception { 44*e7b1675dSTing-Kang Chang if (args.length != 3) { 45*e7b1675dSTing-Kang Chang System.err.printf("Expected 3 parameters, got %d\n", args.length); 46*e7b1675dSTing-Kang Chang System.err.println( 47*e7b1675dSTing-Kang Chang "Usage: java JwtVerify public-jwk-set-file audience token-file"); 48*e7b1675dSTing-Kang Chang System.exit(1); 49*e7b1675dSTing-Kang Chang } 50*e7b1675dSTing-Kang Chang 51*e7b1675dSTing-Kang Chang Path publicJwkSetFile = Paths.get(args[0]); 52*e7b1675dSTing-Kang Chang String audience = args[1]; 53*e7b1675dSTing-Kang Chang Path tokenFile = Paths.get(args[2]); 54*e7b1675dSTing-Kang Chang 55*e7b1675dSTing-Kang Chang // Register all JWT signature key types with the Tink runtime. 56*e7b1675dSTing-Kang Chang JwtSignatureConfig.register(); 57*e7b1675dSTing-Kang Chang 58*e7b1675dSTing-Kang Chang // Read the public keyset in JWK set format into a KeysetHandle. 59*e7b1675dSTing-Kang Chang KeysetHandle publicKeysetHandle = 60*e7b1675dSTing-Kang Chang JwkSetConverter.toPublicKeysetHandle( 61*e7b1675dSTing-Kang Chang new String(Files.readAllBytes(publicJwkSetFile), UTF_8)); 62*e7b1675dSTing-Kang Chang 63*e7b1675dSTing-Kang Chang List<String> lines = Files.readAllLines(tokenFile, UTF_8); 64*e7b1675dSTing-Kang Chang if (lines.size() != 1) { 65*e7b1675dSTing-Kang Chang System.err.printf("The signature file should contain only one line, got %d", lines.size()); 66*e7b1675dSTing-Kang Chang System.exit(1); 67*e7b1675dSTing-Kang Chang } 68*e7b1675dSTing-Kang Chang String signedToken = lines.get(0).trim(); 69*e7b1675dSTing-Kang Chang 70*e7b1675dSTing-Kang Chang // Get the primitive. 71*e7b1675dSTing-Kang Chang JwtPublicKeyVerify verifier = publicKeysetHandle.getPrimitive(JwtPublicKeyVerify.class); 72*e7b1675dSTing-Kang Chang 73*e7b1675dSTing-Kang Chang // Use the primitive to verify a token. 74*e7b1675dSTing-Kang Chang JwtValidator validator = JwtValidator.newBuilder().expectAudience(audience).build(); 75*e7b1675dSTing-Kang Chang VerifiedJwt verifiedJwt = verifier.verifyAndDecode(signedToken, validator); 76*e7b1675dSTing-Kang Chang long seconds = ChronoUnit.SECONDS.between(Instant.now(), verifiedJwt.getExpiration()); 77*e7b1675dSTing-Kang Chang System.out.println("Token is valid and expires in " + seconds + " seconds."); 78*e7b1675dSTing-Kang Chang } 79*e7b1675dSTing-Kang Chang JwtVerify()80*e7b1675dSTing-Kang Chang private JwtVerify() {} 81*e7b1675dSTing-Kang Chang } 82*e7b1675dSTing-Kang Chang // [END java-jwt-verify-example] 83