Skip to content

Instantly share code, notes, and snippets.

@NeilMadden
Created November 19, 2019 14:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save NeilMadden/685ea66fb79d37a50c2310f853bd9496 to your computer and use it in GitHub Desktop.
Save NeilMadden/685ea66fb79d37a50c2310f853bd9496 to your computer and use it in GitHub Desktop.
Example ECDH DPoP using existing JWE ECDH-ES implementation
// Shared context of the request:
String accessToken = "an_access_token";
String origin = "https://api.example.com:443";
JweHeader header = new JweHeader();
header.setAgreementPartyUInfo(Base64url.encode(accessToken));
header.setAgreementPartyVInfo(Base64url.encode(origin));
// Server - generate challenge
OkpJWK ephemeral = OkpJWK.generateKeyPair(X25519);
String challenge = Base64url.encode(ephemeral.toPublicJwk().get().toJsonValue().toString());
System.out.println("WWW-Authenticate: DPoP " + challenge);
// Client - derive HMAC key
OkpJWK staticKeys = OkpJWK.generateKeyPair(X25519);
ECDHDerivedKey ecdh = new ECDHDerivedKey(staticKeys.toPrivateKey(), "HmacSHA256", 256);
ecdh.setTheirPublicKey(ephemeral.toPublicKey());
ecdh.setOtherInfo(ECDHEncryptionHandler.generateOtherInfo(header, "HS256", 256));
SecretKey hmacKey = ecdh.getDerivedKey();
// Client - generate response
String jwt = JOSE.jws(new HmacSigningHandler(hmacKey))
.headers().alg(JwsAlgorithm.HS256).headerIfNotNull("kid", ephemeral.getKeyId()).done()
.claims(JOSE.claims().claim("htm", "POST").claim("htu", "https://api.example.com/foo").build())
.build();
System.out.println("Authorization: DPoP at=" + accessToken + ", jwt=" + jwt);
// Server - validate response
PublicKey confirmationKey = staticKeys.toPublicKey(); // Received from token introspection
ecdh = new ECDHDerivedKey(ephemeral.toPrivateKey(), "HmacSHA256", 256);
ecdh.setTheirPublicKey(confirmationKey);
ecdh.setOtherInfo(ECDHEncryptionHandler.generateOtherInfo(header, "HS256", 256));
hmacKey = ecdh.getDerivedKey();
SignedJwt response = JOSE.reconstruct(jwt, SignedJwt.class);
assertThat(response.verify(new HmacSigningHandler(hmacKey))).isTrue();
@NeilMadden
Copy link
Author

Example output:

WWW-Authenticate: DPoP eyJrdHkiOiJPS1AiLCJjcnYiOiJYMjU1MTkiLCJ4IjoiNWRUT1JBTC0xdEl6UTZTYmZkWmlfN1cyc2dWYU4waVF2NXdSanVMNW5nVSJ9
Authorization: DPoP at=an_access_token, jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJodG0iOiJQT1NUIiwiaHR1IjoiaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20vZm9vIn0.9RGtjElYfjYkTYJuqbawAZQdWrCjPuzCFE4gz3yrzoU

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment