Handshake in JWT public/private key authentication using vertx - java

I created a small vertx auth-server which signs/generates JWT tokens using public/private key.
PrivateKey privateKey = CertUtil.getPrivateKey("config/private_key.der");
PublicKey publicKey = CertUtil.getPublicKey("config/public_key.der");
// Create a JWT Auth Provider
JWTAuth jwt = JWTAuth.create(vertx, new JWTAuthOptions()
.setPubSecKeys(List.of(new PubSecKeyOptions()
.setAlgorithm("RS256")
.setPublicKey(Base64.getEncoder().encodeToString(publicKey.getEncoded()))
.setSecretKey(Base64.getEncoder().encodeToString(privateKey.getEncoded())))));
// protect the API
router.route("/api/*").handler(JWTAuthHandler.create(jwt, "/api/new-token"));
// this route is excluded from the auth handler
router.get("/api/new-token").handler(ctx -> this.generateAndSendToken(ctx, jwt));
// this is the secret API
router.get("/api/protected").handler(ctx -> {
ctx.response().putHeader("Content-Type", "text/plain");
ctx.response().end("a secret you should keep for yourself...");
});
vertx.createHttpServer().requestHandler(router).listen(8080);
now when i access /api/new-token from client i get a JWT token back signed from my auth-server above. however I have some open questions:
How is auth-server making sure that client has server public key and it is genuine?
How can client send public key to auth-server?
How can i make /api/new-token secure so only legitimate client can connect to it?

Why don't you delegate this task to KeyCloak an Open Source Identity and Access Management. It adds authentication to your app and secures services with minimum fuss.
We have used it into our project and it works pretty well!
To plug it with Vert.x, you can follow these tutos :
https://vertx.io/blog/vertx-3-and-keycloak-tutorial/
https://medium.com/#alexpitacci/vert-x-and-keycloak-working-together-9d459a5ebd9e
http://paulbakker.io/java/jwt-keycloak-angular2/
https://piotrminkowski.wordpress.com/2017/09/15/building-secure-apis-with-vert-x-and-oauth2/

Related

Create decryption key from .pem for Azure AD SAML assertion

I'm implementing an integration that needs to authenticate with the SAML protocol.
Everything works fine without the Azure AD Token encryption but when it's active i'm unable to authenticate to the IdP.
I've got the .pem file used for the Token encryption but I can't find documentation on how to use this certificate.
I've tried to import the "encryption.pem" in my keystore that already contains the signing certificate and key that I use to sign the request and response (the certificates are different).
I think it does not work because the .pem file I have is a certificate and I think I need to generate a key pair from that cert.
Can someone point out how to do this with OpenSSL or also Java Keytool?
For more infos I'm posting my code that handles the keystore and the ExtendedMetadata bean where I'm trying to link the .pem certificate i got.
Resource storeFile = loader.getResource(keyStoreLocation);
String storePass = samlKeyStorePassword;
Map<String, String> passwords = new HashMap<>();
passwords.put(samlPrivateKeyAlias, samlPrivateKeyPassword);
String defaultKey = samlPrivateKeyAlias;
return new JKSKeyManager(storeFile, storePass, passwords, defaultKey);
// Setup advanced info about metadata
#Bean
public ExtendedMetadata extendedMetadata() {
ExtendedMetadata extendedMetadata = new ExtendedMetadata();
extendedMetadata.setIdpDiscoveryEnabled(false);
extendedMetadata.setSigningAlgorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
extendedMetadata.setSignMetadata(true);
extendedMetadata.setEncryptionKey("enc"); //THIS IS WHERE I'M TRYING TO PUT MY ENCRYPTION KEY
extendedMetadata.setEcpEnabled(true);
return extendedMetadata;
} ```

Would it be possible to sign a jwt token with a RSA public key? [duplicate]

I'm trying to understand the logic of using JSON web tokens with private/public keys (RS512) when signing a payload of data sent from a client (in this case, a React Native App) to my server.
I thought the whole point of private/public keys was to keep the private key private (on my server) and hand the public key to the person who's successfully logged into the app.
I thought, with each API request to my server, the authenticated user of the app would use the public key to create the JWT (on the client side) and the server would use the private key to verify the signature/payload from the API request.
It seems I have it backwards because everywhere I read, you're supposed to sign a JWT with the private key -- but that goes against my understanding of who's in possession of the keys.
Depending on how the keys are created, some private keys can have a passcode which is supposed to be secret! So if the private key and the secret is out in the open (in client-side code) how secure can that be?
And where does the encryption come in? If the user of the app is sending sensitive data in the API, am I supposed to encrypt the payload and sign it with the JWT on the client side and then let the server verify the JWT signature and decrypt the data?
This tutorial was helpful https://medium.com/#siddharthac6/json-web-token-jwt-the-right-way-of-implementing-with-node-js-65b8915d550e but it seems backwards.
Any explanation would definitely help because all of the on-line tutorials aren't making sense.
Thank you.
With JWT, the possession and the use of the key materials are exactly the same as any other contexts where cypher operations occur.
For signing:
The private key is owned by the issuer and is used to compute the signature.
The public key can be shared with all parties that need to verify the signature.
For encryption:
The private key is owned by the recipient and is used to decrypt the data.
The public key can be shared to any party that want to send sensitive data to the recipient.
The encryption is rarely used with JWT. Most of the time the HTTPS layer is sufficient and the token itself only contain a few information that are not sensitive (datatime, IDs...).
The issuer of the token (the authentication server) has a private key to generate signed tokens (JWS). These tokens are sent to the clients (an API server, a web/native application...).
The clients can verify the token with the public key. The key is usually fetched using a public URI.
If you have sensitive data that shall not be disclosed to a third party (phone numbers, personnal address...), then the encrypted tokens (JWE) is highly recommended.
In this case, each client (i.e. recipient of a token) shall have a private key and the issuer of the token must encrypt the token using the public key of each recipient. This means that the issuer of the token can select the appropriate key for a given client.
Hope this figure adds some clarity.
Solution for JWE in React Native and Node Backend
The hardest part was finding a method that works in both RN and Node because I can't just use any Node library in RN.
I'm transmitting all of the API calls over HTTPS.
Create a JWE to encrypt the token and payload simultaneously.
React Native App Code
import {JWK, JWE} from 'react-native-jose';
/**
* Create JWE encrypted web token
*
* #param payload
* #returns {Promise<string>}
*/
async function createJWEToken(payload = {}) {
// This is the Public Key created at login. It is stored in the App.
// I'm hard-coding the key here just for convenience but normally it
// would be kept in a Keychain, a flat file on the mobile device, or
// in React state to refer to before making the API call.
const publicKey = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApl9FLYsLnP10T98mT70e
qdAeHA8qDU5rmY8YFFlcOcy2q1dijpgfop8WyHu1ULufJJXm0PV20/J9BD2HqTAK
DZ+/qTv4glDJjyIlo/PIhehQJqSrdIim4fjuwkax9FOCuFQ9nesv32hZ6rbFjETe
QSxUPjNzsYGOuULWSR3cI8FuV9InlSZQ7q6dEunLPRf/rZujxiAxGzY8zrMehjM5
LNdl7qDEOsc109Yy3HBbOwUdJyyTg/GRPwklLogw9kkldz5+wMvwOT38IlkO2rCr
qJpqqt1KmxdOQNbeGwNzZiGiuYIdiQWjilq5a5K9e75z+Uivx+G3LfTxSAnebPlE
LwIDAQAB
-----END PUBLIC KEY-----`;
try {
const makeKey = pem => JWK.asKey(pem, 'pem');
const key = await makeKey(publicKey);
// This returns the encrypted JWE string
return await JWE.createEncrypt({
zip: true,
format: 'compact',
}, key).update(JSON.stringify(payload)).final();
} catch (err) {
throw new Error(err.message);
}
}
Node Backend
const keygen = require('generate-rsa-keypair');
const {JWK, JWE} = require('node-jose');
/**
* Create private/public keys for JWE encrypt/decrypt
*
* #returns {Promise<object>}
*
*/
async function createKeys() {
// When user logs in, create a standard RSA key-pair.
// The public key is returned to the user when he logs in.
// The private key stays on the server to decrypt the message with each API call.
// Keys are destroyed when the user logs out.
const keys = keygen();
const publicKey = keys.public;
const privateKey = keys.private;
return {
publicKey,
privateKey
};
}
/**
* Decrypt JWE Web Token
*
* #param input
* #returns {Promise<object>}
*/
async function decryptJWEToken(input) {
// This is the Private Key kept on the server. This was
// the key created along with the Public Key after login.
// The public key was sent to the App and the Private Key
// stays on the server.
// I'm hard-coding the key here just for convenience but
// normally it would be held in a database to
// refer during the API call.
const privateKey = `-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEApl9FLYsLnP10T98mT70eqdAeHA8qDU5rmY8YFFlcOcy2q1di
jpgfop8WyHu1ULufJJXm0PV20/J9BD2HqTAKDZ+/qTv4glDJjyIlo/PIhehQJqSr
dIim4fjuwkax9FOCuFQ9nesv32hZ6rbFjETeQSxUPjNzsYGOuULWSR3cI8FuV9In
lSZQ7q6dEunLPRf/rZujxiAxGzY8zrMehjM5LNdl7qDEOsc109Yy3HBbOwUdJyyT
g/GRPwklLogw9kkldz5+wMvwOT38IlkO2rCrqJpqqt1KmxdOQNbeGwNzZiGiuYId
iQWjilq5a5K9e75z+Uivx+G3LfTxSAnebPlELwIDAQABAoIBAQCmJ2FkMYhAmhOO
LRMK8ZntB876QN7DeT0WmAT5VaE4jE0mY1gnhp+Zfn53bKzQ2v/9vsNMjsjEtVjL
YlPY0QRJRPBZqG3wX5RcoUKsMaxip3dckHo3IL5h0YVJeucAVmKnimIbE6W03Xdn
ZG94PdMljYr4r9PsQ7JxLOHrFaoj/c7Dc7rd6M5cNtmcozqZsz6zVtqO1PGaNa4p
5mAj9UHtumIb49e3tHxr//JUwZv2Gqik0RKkjkrnUmFpHX4N+f81RLDnKsY4+wyI
bM5Gwq/2t8suZbwfHNFufytaRnRFjk+P6crPIpcfe05Xc+Y+Wq4yL62VY3wSS13C
EeUZ2FXpAoGBANPtw8De96TXsxdHcbmameWv4uepHUrYKq+7H+pJEGIfJf/1wsJ0
Gc6w2AE69WJVvCtTzP9XZmfiIze2sMR/ynhbUl9wOzakFpEh0+AmJUG+lUHOy4k2
Mdmu6GmeIM9azz6EXyfXuSZ39LHowS0Es1xaWRuu5kta73B5efz/hz2tAoGBAMj4
QR87z14tF6dPG+/OVM/hh9H5laKMaKCbesoXjvcRVkvi7sW8MbfxVlaRCpLbsSOs
cvAkc4oPY+iQt8fJWSJ1nwGJ0g7iuObLJh9w6P5C3udCGLcvqNbmQ9r+edy1IDBr
t7pdrFKiPFvaEEqYl06gVSsPCg041N6bRTJ1nEzLAoGAajSOVDqo6lA6bOEd6gDD
PSr+0E+c4WQhSD3Dibqh3jpz5aj4uFBMmptfNIaicGw8x43QfuoC5O6b7ZC9V0wf
YF+LkU6CLijfMk48iuky5Jao3/jNYW7qXofb6woWsTN2BoN52FKwc8nLs9jL7k6b
wB166Hem636f3cLS0moQEWUCgYABWjJN/IALuS/0j0K33WKSt4jLb+uC2YEGu6Ua
4Qe0P+idwBwtNnP7MeOL15QDovjRLaLkXMpuPmZEtVyXOpKf+bylLQE92ma2Ht3V
zlOzCk4nrjkuWmK/d3MzcQzu4EUkLkVhOqojMDZJw/DiH569B7UrAgHmTuCX0uGn
UkVH+wKBgQCJ+z527LXiV1l9C0wQ6q8lrq7iVE1dqeCY1sOFLmg/NlYooO1t5oYM
bNDYOkFMzHTOeTUwbuEbCO5CEAj4psfcorTQijMVy3gSDJUuf+gKMzVubzzmfQkV
syUSjC+swH6T0SiEFYlU1FTqTGKsOM68huorD/HEX64Bt9mMBFiVyA==
-----END RSA PRIVATE KEY-----`;
try {
const makeKey = pem => JWK.asKey(pem, 'pem');
const key = await makeKey(privateKey);
// This returns the decrypted data
return await JWE.createDecrypt(key).decrypt(input);
} catch (err) {
throw new Error(err.message);
}
}
jwt.io does a great job of explaining that there is more than one way to sign the JWT. Users may sign and verify with a single secret, or use a public/private key pair for verifying/signing respectively.
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.
Although JWTs can be encrypted to also provide secrecy between
parties, we will focus on signed tokens. Signed tokens can verify the
integrity of the claims contained within it, while encrypted tokens
hide those claims from other parties. When tokens are signed using
public/private key pairs, the signature also certifies that only the
party holding the private key is the one that signed it.

When to create client id and secret for an API,during Login or Registartion?

I am creating an API and there are multiple clients,So I am implementing a client id-secret artitechure.My questions are:
When should I create the client id and secret? during registration of Login?
How should I connect users to respective client ids?
How should I store client ids and secret?
the client id and secret ( client credentials in OAuth2) use to communicate between server and server ( because secret key stored in server web, where secure with anyone want to access without permission), if for user web I refer you use authorization code flow
each client have a client id (unique per resource)
store in the table with client id, password (encode by md5, ...), role, scope, ... and using it to verify, then create a new token for the client. the client will use a token to request your API, just use secret when need refresh token or create a new token

JWT Introspection middleware with a Web API - Java and Identity Server

I am currently using Identity Server 4 which is .Net Core based to issue JWT tokens. I have a .Net Core web api that has middleware in order for the JWT to be validated in the Startup.cs:
services.AddAuthentication("Bearer")
.AddJwtBearer("Bearer", options =>
{
options.Authority = "http://localhost:5005";
options.Audience = "api1";
});
As we can see, its not asking for much except the location of the token server and who the api is which is `api1. Obviously, its doing some more complex things under the hood.
I found a Java based equivalent to the middleware above, which validates a JWT:
String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
RSAPublicKey publicKey = //Get the key instance
RSAPrivateKey privateKey = //Get the key instance
try {
Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey);
JWTVerifier verifier = JWT.require(algorithm)
.withIssuer("auth0")
.build(); //Reusable verifier instance
DecodedJWT jwt = verifier.verify(token);
} catch (JWTVerificationException exception){
//Invalid signature/claims
}
This is from HERE as was recommended by the jwt.io site.
Basically I want to be able to implement something in Java that is doing the same thing as the .Net Core code above, but its clearly asking for things like a Public and Private key that I have no idea how to provide at this point, as the JWT is coming through the header of the request.
Under the hood, the Microsoft JWT middleware is going to IdentityServer's discovery endpoint and loading in configuration such as the issuer and JWKS (public keys). The discovery document is always hosted on /.well-known/openid-configuration.
To validate the token, you will at least need the public keys from the JWKS. In the past I've loaded it it using the jwks-rsa library: https://www.scottbrady91.com/Kotlin/JSON-Web-Token-Verification-in-Ktor-using-Kotlin-and-Java-JWT
When validating the access token, as a minimum, you'll also need to check the token's audience (is the token intended for you) and if it has expired.

Get access to REST API using JWT security token

I have RSA key in format
<RSAKeyValue>
<Modulus> ..</Modulus>
<Exponent>..</Exponent>
...
</RSAKeyValue>
I need to get connection to REST API using java.
I should use JWT security token with schema “TokenIssuer”.
Nimbus library provide following example for doing it. Will it help me or I need something else? If yes, where should I write RSA key?
// RSA signatures require a public and private RSA key pair,
// the public key must be made known to the JWS recipient in
// order to verify the signatures
KeyPairGenerator keyGenerator = KeyPairGenerator.getInstance("RSA");
keyGenerator.initialize(1024);
KeyPair kp = keyGenerator.genKeyPair();
RSAPublicKey publicKey = (RSAPublicKey)kp.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey)kp.getPrivate();
// Create RSA-signer with the private key
JWSSigner signer = new RSASSASigner(privateKey);
// Prepare JWT with claims set
JWTClaimsSet claimsSet = new JWTClaimsSet();
claimsSet.setSubject("alice");
claimsSet.setIssueTime(new Date());
claimsSet.setIssuer("https://c2id.com");
SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.RS256), claimsSet);
// Compute the RSA signature
signedJWT.sign(signer);
// To serialize to compact form, produces something like
// eyJhbGciOiJSUzI1NiJ9.SW4gUlNBIHdlIHRydXN0IQ.IRMQENi4nJyp4er2L
// mZq3ivwoAjqa1uUkSBKFIX7ATndFF5ivnt-m8uApHO4kfIFOrW7w2Ezmlg3Qd
// maXlS9DhN0nUk_hGI3amEjkKd0BWYCB8vfUbUv0XGjQip78AI4z1PrFRNidm7
// -jPDm5Iq0SZnjKjCNS5Q15fokXZc8u0A
String s = signedJWT.serialize();
// To parse the JWS and verify it, e.g. on client-side
signedJWT = SignedJWT.parse(s);
JWSVerifier verifier = new RSASSAVerifier(publicKey);
assertTrue(signedJWT.verify(verifier));
// Retrieve the JWT claims
assertEquals("alice", signedJWT.getJWTClaimsSet().getSubject());
From my perspective, if you want use RSA, then I suggest to use nested signed and encrypted JWT.
In that way the server can sign JWT with public key, and then the client can decrypt JWT with private key and validate that JWT.
From the perspective of storing the keys, you can store them on the file system, provide some kind configuration property to point to that file, or because it's public key, you can get that key from some services, or you can request it from the client.
Same approach you can take with storing private keys on client side.
But I think for most scenarios is acceptable to use nested signed and encrypted JWT with simple HMAC protection.
Because client will request authentication, and he will send received token to server, and the server will do validation of JWT token.
You can look at the Nimbus example http://connect2id.com/products/nimbus-jose-jwt/examples/signed-and-encrypted-jwt

Categories

Resources