A note on how to generate / validate an Open ID Connect / ID token in Java.
OpenSSL is used to generate the private key and public key for signing.
** 1. Generate a private key. ** **
#Generate a private key in PEM format.
openssl genrsa -out jwt-private-key.pem 2048
#PKCS8 private key in PEM format/Convert to DER format.
openssl pkcs8 -in jwt-private-key.pem -topk8 -nocrypt -outform DER -out jwt-private-key.pk8
** 2. Generate a public key. ** **
#Generate a public key in DER format.
openssl rsa -in jwt-private-key.pem -pubout -outform DER -out jwt-public-key.der
** 3. Base64-encode the private key (jwt-private-key.pk8
) and public key (jwt-public-key.der
) and save them in a configuration file. ** * Implemented according to the use case.
Obtain the private key as RSA PrivateKey
type and the public key as RSAPublicKey
type from the signature information (Base64 encoded character string) stored in the configuration file or DB.
/**
*Get the RSA private key from the Base64 encoded string.
*/
private RSAPrivateKey getRSAPrivateKeyFromBase64String() throws NoSuchAlgorithmException,InvalidKeySpecException {
String privateKeyAsBase64String = "Base64 format private key * Acquisition process omitted";
byte[] privateKeyAsByteArray = Base64.decodeBase64(privateKeyAsBase64String);
PKCS8EncodedKeySpec pkcs8ks = new PKCS8EncodedKeySpec(privateKeyAsByteArray);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privateKey = kf.generatePrivate(pkcs8ks);
return (RSAPrivateKey)privateKey;
}
...
/**
*Get the RSA public key from the Base64 encoded string.
*/
private RSAPublicKey getRSAPublicKeyFromBase64String() throws NoSuchAlgorithmException,InvalidKeySpecException{
String publicKeyAsBase64String = "Base64 format public key * Acquisition process omitted";
byte[] publicKeyAsByteArray = Base64.decodeBase64(publicKeyAsBase64String);
X509EncodedKeySpec x509ks = new X509EncodedKeySpec(publicKeyAsByteArray);
KeyFactory kf = KeyFactory.getInstance("RSA");
PrivateKey privateKey = kf.generatePublic(x509ks);
return (RSAPublicKey)publicKey;
}
...
/**
* Base64 URL-Generate an ID token in encoded format.
* sub:ID token issue destination subject(User ID)
* aud:ID token issuance destination client ID
* acr:Authentication context
*/
public String createIDToken(String sub, String aud, String acr) throws ParseException, JOSEException {
//Payload preparation
//Token issuer information
String iss = "Issuer information acquired from configuration files, etc. * Acquisition processing omitted";
//Token issuance date and time
Date iat = new Date();
//Token expiration date( =Issue date and time+Validity period)
Long expiresIn = "Token validity period acquired from configuration file or DB * Acquisition process omitted";
Date exp = new Date(iat.getTime() + expiresIn * 1000);
IDTokenClaimSet cs = new IDTokenClaimSet(new Issuer(iss), new Subject(subject), Arrays.asList(new Audience(aud)), exp, iat);
//Set necessary claims such as authentication context...
cs.setACR(new ACR(acr));
SignedJWT jwt = new SignedJWT(new JWSHeader(JWSAlgorithm.RS256),cs.toJWTClaimSet());
//signature
jwt.sign(new RSASSASigner(getRSAPrivateKeyFromBase64String()));
// Base64 URL-Convert to encoded format
return jwt.serialize();
}
/**
*Perform ID token verification processing.
*/
public Boolean verifyIDToken(String idToken) throws ParseException, JOSEException {
SignedJWT jwt = SignedJWT.parse(idToken);
//Signature verification
RSASSAVerifier verifier = new RSASSAVerifier(getRSAPublicKeyFromBase64String());
if(false == jwt.verify(verifier)){
return false;
}
//Payload perspective
JWTClaimSet cs = jwt.getJWTClaimSet();
//iss verification
String iss = "Issuer information acquired from the configuration file or DB * Acquisition process omitted";
if(!iss.equals(cs.getIssuer())){
return false;
}
//exp verification
if(new Date().after(cs.getExpirationTime())){
return false;
}
//aud verification
String aud = "Client ID issued to itself";
if(!aud.equals(cs.getAudience().get(0))){
return false;
}
//Verify other claims such as other acr...
return true;
}
Recommended Posts