i have a problem that when i create claim after signing it while sending i am getting key is not valid, not able to get the reason ..
*code:*
OctetSequenceJsonWebKey key = OctJwkGenerator.generateJwk(2048);
JsonWebSignature jws = new JsonWebSignature();
jws.setKey(key.getKey());
jws.setPayload(claims.toJson());
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.HMAC_SHA256);
signedJWT = jws.getCompactSerialization();
return signedJWT;
For Hmac algorithms, you are supposed to use an octet key.
From your code, I can see you are loading a RSA key (RsaJsonWebKey)
Related
I'm trying to implement MTLS client authentication using AWS ACM Private CA to issue X.509 client certificates.
The certificate and the correlating private key is supposed to be stored in a password protected PKCS#12 file.
The private key will also be used by the client to sign data.
If I request a new certificate using aws-acm-sdk:
RequestCertificateResult response = acm.requestCertificate(new RequestCertificateRequest()
.withCertificateAuthorityArn(CA_ARN)
.withIdempotencyToken("1234")
.withDomainName("localhost.com"));
return response.getCertificateArn();
And then export the it using the arn, I get a certificate, certificateChain and a privateKey as strings.
ExportCertificateResult response = acm.exportCertificate(new ExportCertificateRequest()
.withCertificateArn(certificateArn)
.withPassphrase(ByteBuffer.wrap(password.getBytes())));
String certificate = response.getCertificate();
String certificateChain = response.getCertificateChain();
String privateKey = response.getPrivateKey();
But I'm not able to add any type of identifier that let's me tie the certificate to a user during authentication (I'm using Java and Spring security x509 authentication, which extracts e.g. the subject CN (Common Name) from the certificate which then can be used to identify a user).
If I want to add custom attributes to the certificate, I need to issue a certificate through the aws-acm-pca-sdk:
IssueCertificateRequest request = new IssueCertificateRequest()
.withCertificateAuthorityArn(CA_ARN)
.withCsr(stringToByteBuffer(getCSR()))
.withTemplateArn("arn:aws:acm-pca:::template/EndEntityClientAuthCertificate_APIPassthrough/V1")
.withSigningAlgorithm(SigningAlgorithm.SHA256WITHRSA)
.withValidity(new Validity()
.withValue(365L)
.withType(ValidityPeriodType.DAYS))
.withIdempotencyToken(userId)
.withApiPassthrough(new ApiPassthrough()
.withSubject(new ASN1Subject()
.withCustomAttributes(List.of(
new CustomAttribute()
.withObjectIdentifier("1.3.6.1.4.1") // CustomOID
.withValue("userId")))));
return acmPca.issueCertificate(request).getCertificateArn();
But if I use the sdk to get the certificate, it doesn't contain any private key.
GetCertificateResult response = acmPca.getCertificate(new GetCertificateRequest()
.withCertificateAuthorityArn(CA_ARN)
.withCertificateArn(certificateArn));
String certificate = response.getCertificate();
String certificateChain = response.getCertificateChain();
So, when I read documentation I found that I need to import it to ACM in order to export it and get the private key.
But in order to import it to ACM I also need to provide the private key..
But as I understand it, the private key should be used when issuing the certificate in the first place?
Should I create a new public/private key pair using KMS or what am I supposed to do?
Im confused.. Please help!
I had misinterpreted the responsibility of the PCA.
The PCA is only responsible for issuing certificates, not keys or even CSR (Certificate Signing Requests).
I assumed that the CSR were created by PCA, so the getCSR() method actually fetched the CA's CSR from PCA, while the actual CSR should be generated internally using a private key which has been generated either programmatically or using KMS.
I use the /auth/realms//protocol/openid-connect/certs endpoint and hardcode the x5c public key returned from this endpoint to try to get this code working (wrapped in BEGIN RSA/END RSA tags) like so:
let x5c = "MIICnTCCAYUCBgF9TkI2ijANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdldmlkZW5zMB4XDTIxMTEyMzE5MjMyMVoXDTMxMTEyMzE5MjUwMVowEjEQMA4GA1UEAwwHZXZpZGVuczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALgx8kfUyhUz6146LcXJHykE5d/kfkJGHZ1+AH4wfk0Z1rGeNqRUH7bllutre2xrq/EfuKGkuUul8uf7WH3GTyOFJyr1MECnzilYdN8onobpVHXr3SwANCACMsh6tFc6oiQT0XEt1ovzTzB6vxA6qmmsdLPG9giJ9eNqJNHHQiIJosF3yBBoNFDiQDonRNdWNQz5JVxbsdIOhFrdD+mDU0ry9FIs6qMAvD84QVBOzJr/IOCdSy3bfWYyAUsLHqoJbytAzl5EgjVSU2UT+HLs7M2wfZoRGITztmvkcPjqd7PnSOuuAimonwP7uKHtvG+edRabyHaBDSemEA1LUs7+FGkCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAIh4QCe6Y3fJtDV6nBi/E3CGo/SIjDCmNnOV413QtmwODZSWFqo6pxs2fJoDb8jIkTf+l8/bI+mKEesXK1CptBpXXyo7Il0jhk5M0c1VT7EkLa/jkVFNr0CoB3UmH56/29Qp8+Xr8TaejGjgS8HoxAMpSFrtjPlKElCcy8dVQgRMxFonry5Iipd4vutc8Afe/GLzJew0IJ5Az1VUum3bJD0IfeecB8F+YOMmaET0oJIQyfdUxVI985Ui30q4K8/p34+WqwvNy2x4vuulvDVRBsHG64PStzhqZQfsfi59lOps4WvYlQ1JEHTu3acZMyTzij6wrVTAFoh1C3FptZ0wPoQ==";
let pemEncoded = `-----BEGIN RSA PUBLIC KEY-----\n${x5c}\n-----END RSA PUBLIC KEY-----\n`;
const payload = verify(token, pemEncoded, { "algorithms": ["RS256"] }));
But I don't think I've got correct PEM and I've been at it all day trying to find how to setup this certificate for verification. The error says "error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag". The token is valid, but it doesn't like my certificate. Any idea what I've got wrong here?
What's the correct way to pass this certificate to the jsonwebtoken.verify method in this case? Thanks!
That is certificate, so:
let pemEncoded = `-----BEGIN CERTIFICATE-----\n${x5c}\n-----END CERTIFICATE-----\n`;
I'm new to JWT. I've noticed that a lot of people place the private and public keys in separate files, and then load the content of the files when creating the JWT.
For example:
const fs = require('fs');
const jwt = require('jsonwebtoken');
const privateKEY = fs.readFileSync('./private.key', 'utf8');
const publicKEY = fs.readFileSync('./public.key', 'utf8');
let token = jwt.sign(payload, privateKEY, signOptions);
I don't know if I'm misunderstanding the concept of something but doesn't that make every key the same? And what is the point of having keys if they're all the same? Let's say I'm creating a server that stores a user's login information and assigns a private and public key to each user. That would mean that ever key-pair would have to be unique right? I obviously want the keys to be generated automatically for each user. What is the correct way to create an unique key-pair for a user when using JWT?
I have a problem with JWT. If someone decompiles my APK, they can see the secret code I used to create my token. Example code, the code is secret:
String originalInput = "secret";
String encodedString =Base64Utils.encode(originalInput.getBytes());
String jwt = Jwts.builder().claim("emailId","test123#gmail.com").claim("user", "123456")
.claim("phoneNo", "1111111111")
.signWith(SignatureAlgorithm.HS256, encodedString)
.compact();
As there are a client (the APK) and a backend, you should use an asymmetric algorithm such as RS256, PS256 or ES256, not a symmetric one (HS256).
If the issuer of the token is your backend, you only need the public key on client side (your APK). This key can safely be shipped as it is public.
If the client is the issuer, key should not be shipped with your application but generated on the device and securely stored using the Keystore API (https://developer.android.com/training/articles/keystore). The associated public key should be sent to the backend. This means that each client has a uniquely generated private key.
I'm writing backend microservice that receives requests from front-end which have Authorisation: Bearer ... header, with token obtained from keycloak (which is inside docker container).
I got the RSA public key to verify the signature of that token from Keys section of realm settings, but it seems that when container with keycloak restarts, it regenerates pair of keys, and my public key set in service config becomes invalid.
What is the proper way to work with RSA public key from keycloak? Is there some way to configure it to use a fixed pair of keys for realm? Are keys exported when realm exports? Or I have to get the public key from keycloak using url like http://keycloak:8080/auth/realms/:realm_name:, which I rather not to do because this adds a dependency between keycloak and backend.
You should verify the JWT token's signature based on the issuer identity server's /.well-known/jwks endpoint.
1) Query the issuer identity server's /.well-known/jwks endpoint (JWKS stands for JSON Web Key Set)
2) From the JWKS, get the JWK (JSON Web Key) with the same kid (Key ID) as the Bearer token we are verifying. To get the kid from your JWT token, first decode it using jwt.io's Debugger tool.
3) As long as identity server-issued tokens are verified with an asymmetric cryptography algorithm (e.g.: RS256), we can verify the signature with the Public Key only (so you won't need the Private Key)
4) The Public Key can be retrieved from the JWK (it is the x5c entry in the JWK JSON )
5) Verify the JWT Bearer token's signature with this Public Key.
For example, in Java you can verify it like this:
// verify JWT signature based on Access Identity's JWKS RSA public key (RS256)
try {
Jwk jwk = new UrlJwkProvider(new URL(issuer + Constants.JWKS_ENDPOINT)).get(decodedJWT.getKeyId());
final PublicKey publicKey = jwk.getPublicKey();
if (!(publicKey instanceof RSAPublicKey)) {
throw new IllegalArgumentException("Key with ID " + decodedJWT.getKeyId() + " was found in JWKS but is not a RSA-key.");
}
Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) publicKey, null);
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer(issuer)
.build(); //Reusable verifier instance
verifier.verify(bearerToken);
LOGGER.info("Token verified!");
} catch (Exception e) {
LOGGER.error(e.getMessage());
throw new InvalidAccessTokenException("JWTVerificationException - Invalid token signature.");
}