-
Hi, I cannot get private_key_jwt to work with Azure AD. I started with a working configuration using OIDCClientSecret, but when shifting to private_key_jwt I get errors back from Azure:
I tried using curl manually with the same certificate & key combination and it worked. My configuration is as below. The customKeyIdentifier in Azure matches the fingerprint of the X.509 certificate.
Looking at the logging, it appears that mod_auth_openidc is sending a client_assertion of the form:
Whereas, according to Azure documentation is expecting:
The differences being: x5t instead of kid, missing typ, token missing from end of aud. Does this mean that mod_auth_openidc is not compatible with Azure AD for private_key_jwt? |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 9 replies
-
both mod_auth_openidc and Azure AD are certified implementations of OpenID Connect including their usage of |
Beta Was this translation helpful? Give feedback.
-
I am not sure that is correct. The Microsoft documentation clearly stats "x5t" is required in the header and mod_auth_openidc sends "kid" - I am not an expert on JWT so I don't know how significant that is, but it is different. To test this, I took the HTTP request from the Apache debug logs (oidc_util_http_call: url=) and constructed a curl command line that did the same thing. This gives the same error - AADSTS700027: Client assertion contains an invalid signature - so is a replica. I then put the client_assertion= data into an online JWT encoder/decoder. Uploaded the same certificate that is in Azure and in Apache OIDC config. I changed the header to contain "x5t" and took the SHA1 fingerprint base64 encoded, as per Microsoft docs. After making this change, and only changing the client_assertion= block of curl, it works. Some additional background:
|
Beta Was this translation helpful? Give feedback.
-
this should be better: diff --git a/src/jose.c b/src/jose.c
index 9423500..ee1f25f 100644
--- a/src/jose.c
+++ b/src/jose.c
@@ -880,6 +880,8 @@ apr_byte_t oidc_jwt_sign(apr_pool_t *pool, oidc_jwt_t *jwt, oidc_jwk_t *jwk,
oidc_jwt_hdr_set(jwt, CJOSE_HDR_KID, jwt->header.kid);
if (jwt->header.enc)
oidc_jwt_hdr_set(jwt, CJOSE_HDR_ENC, jwt->header.enc);
+ if (jwt->header.x5t)
+ oidc_jwt_hdr_set(jwt, OIDC_JOSE_JWK_X5T_STR, jwt->header.x5t);
if (jwt->cjose_jws)
cjose_jws_release(jwt->cjose_jws);
diff --git a/src/jose.h b/src/jose.h
index 5bbc20f..96773b5 100644
--- a/src/jose.h
+++ b/src/jose.h
@@ -204,6 +204,8 @@ typedef struct oidc_jwt_hdr_t {
char *kid;
/* JWT "enc" claim value; encryption algorithm */
char *enc;
+ /* JWT "x5t" thumbprint */
+ char *x5t;
} oidc_jwt_hdr_t;
/* parsed JWT payload */
diff --git a/src/proto.c b/src/proto.c
index a9b79c4..b689255 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -1866,13 +1866,11 @@ static apr_byte_t oidc_proto_endpoint_access_token_bearer(request_rec *r,
#define OIDC_PROTO_JWT_ASSERTION_ASYMMETRIC_ALG CJOSE_HDR_ALG_RS256
-static apr_byte_t oidc_proto_endpoint_auth_private_key_jwt(request_rec *r,
- oidc_cfg *cfg, const char *client_id,
- const apr_array_header_t *client_signing_keys, const char *audience,
+static apr_byte_t oidc_proto_endpoint_auth_private_key_jwt(request_rec *r, oidc_cfg *cfg,
+ const char *client_id, const apr_array_header_t *client_signing_keys, const char *audience,
apr_table_t *params) {
oidc_jwt_t *jwt = NULL;
oidc_jwk_t *jwk = NULL;
- const apr_array_header_t *signing_keys = NULL;
oidc_debug(r, "enter");
@@ -1880,18 +1878,20 @@ static apr_byte_t oidc_proto_endpoint_auth_private_key_jwt(request_rec *r,
return FALSE;
if ((client_signing_keys != NULL) && (client_signing_keys->nelts > 0)) {
- signing_keys = client_signing_keys;
+ jwk = ((oidc_jwk_t**) client_signing_keys->elts)[0];
+ jwt->header.x5t = apr_pstrdup(r->pool, jwk->x5t);
} else if ((cfg->private_keys != NULL) && (cfg->private_keys->nelts > 0)) {
- signing_keys = cfg->private_keys;
+ jwk = ((oidc_jwk_t**) cfg->private_keys->elts)[0];
+ if (cfg->public_keys->nelts > 0)
+ // populate x5t; at least required for Azure AD
+ jwt->header.x5t =
+ apr_pstrdup(r->pool, ((oidc_jwk_t**) (cfg->public_keys->elts))[0]->x5t);
} else {
- oidc_error(r,
- "no private keys have been configured to use for private_key_jwt client authentication (" OIDCPrivateKeyFiles ")");
+ oidc_error(r, "no private keys have been configured to use for private_key_jwt client authentication (" OIDCPrivateKeyFiles ")");
oidc_jwt_destroy(jwt);
return FALSE;
}
- jwk = ((oidc_jwk_t**) signing_keys->elts)[0];
-
jwt->header.kid = apr_pstrdup(r->pool, jwk->kid);
jwt->header.alg = apr_pstrdup(r->pool, CJOSE_HDR_ALG_RS256);
|
Beta Was this translation helpful? Give feedback.
this should be better: