Skip to content

Keyfunc Error: failed to create JWK from JWK Marshal: failed to validate JSON Web Key: failed to validate JWK: X5T in marshal does not match X5T in marshalled #150

Description

@coreybrowndev

Title

JWK validation fails with "X5T in marshal does not match X5T in marshalled" when fetching Auth0's JWKS endpoint

Environment

  • github.com/MicahParks/keyfunc/v3 (latest)
  • github.com/golang-jwt/jwt/v5
  • JWKS source: Auth0 (https://<tenant>.auth0.com/.well-known/jwks.json)
  • Go version: 1.26.4

Description

When using keyfunc.NewDefaultCtx to build a Keyfunc from an Auth0 JWKS endpoint, every background refresh fails validation with the following error, and no keys are ever loaded:

ERROR Failed to refresh HTTP JWK Set from remote HTTP resource. error="failed to create JWK from JWK Marshal: failed to validate JSON Web Key: failed to validate JWK: X5T in marshal does not match X5T in marshalled" url=https://<tenant>.auth0.com/.well-known/jwks.json

Because the JWK Set never loads successfully, every subsequent jwt.Parse call using k.Keyfunc fails, resulting in 401s for all incoming requests.

Steps to Reproduce

const serverURL = "https://redacted.auth0.com/.well-known/jwks.json"
k, err := keyfunc.NewDefaultCtx(ctx, []string{serverURL})
if err != nil {
    log.Fatalf("Failed to create a keyfunc.Keyfunc from the server's URL.\nError: %s", err)
}

parsedToken, err := jwt.Parse(
    token,
    k.Keyfunc,
    jwt.WithValidMethods([]string{jwt.SigningMethodRS256.Alg()}),
    jwt.WithAudience(validationAudience),
    jwt.WithIssuer(validationIssuer),
)

JWKS Payload

{
    "keys": [
        {
            "kty": "RSA",
            "use": "sig",
            "n": "4mKUhg1ZOo0mriez3LWBGoXvp8eXs_cCy4nXYyD0duKl_i-eDPzzWZ0nqrfzPLnnQS13XdJ8RyET0NXSyUaxGSVBbQvbHFc9ocq59jTmuHC-xQlnWsXVEwBacMLRIu8m3sfZoiJcqpvctLZtygCP5nATe7mPSPYAFQx_UK5Hkr5mJP7dIObQLFLLvq7mbTgzjfPdOiH2P-1SnCatJ2fpMQe0qdktEI8WekHI3vRTPerVr8h5JEps5QKpvppK3jcj1_Ezg1Kt_AfsWSTrVgUQzG5VvEnAFHYvs_cfZ74gq_p9yyxi-nvfuzvVI8ZqCetqekqncOXKLMn61NqfY3T2Hw",
            "e": "AQAB",
            "kid": "QzczNUNGNzFEMzQ0REU0M0MxNEY0N0M5M0FGRDVERjkyQzRBM0UzMg",
            "x5t": "QzczNUNGNzFEMzQ0REU0M0MxNEY0N0M5M0FGRDVERjkyQzRBM0UzMg",
            "x5c": [
                "MIIDBzCCAe+gAwIBAgIJOo90qX3gnxJBMA0GCSqGSIb3DQEBCwUAMCExHzAdBgNVBAMTFmRldi1xb3A5czlvci5hdXRoMC5jb20wHhcNMTkwNzAzMjA0MDQ3WhcNMzMwMzExMjA0MDQ3WjAhMR8wHQYDVQQDExZkZXYtcW9wOXM5b3IuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4mKUhg1ZOo0mriez3LWBGoXvp8eXs/cCy4nXYyD0duKl/i+eDPzzWZ0nqrfzPLnnQS13XdJ8RyET0NXSyUaxGSVBbQvbHFc9ocq59jTmuHC+xQlnWsXVEwBacMLRIu8m3sfZoiJcqpvctLZtygCP5nATe7mPSPYAFQx/UK5Hkr5mJP7dIObQLFLLvq7mbTgzjfPdOiH2P+1SnCatJ2fpMQe0qdktEI8WekHI3vRTPerVr8h5JEps5QKpvppK3jcj1/Ezg1Kt/AfsWSTrVgUQzG5VvEnAFHYvs/cfZ74gq/p9yyxi+nvfuzvVI8ZqCetqekqncOXKLMn61NqfY3T2HwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRM0XxeTlV//5G7eN+A3wQqzTEVPDAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADggEBAMtjDuuv4K22q2drPKZ0PD73cuYHbO1D7hmv1Kn7cpuiu18r4k5hevkvM7LBfda2uN++lbWfEc5PZ420qR3dZO5Fpoxrcgm2F7Tv3eOjmCWibrPsc2+hyk/VxK+9zFktzNosRC/Yza6diXn5Uk4+e3TRbfUs1PZl9ShzM3mCktSYd0+dxbHpkU2JtKPaDDqAmQOBGapKpt2NnXgGwMeV2SiMmF6hidVeWHxSy0UpicNRg2qPmqzoemVNhyqNc/N6xwI3SjGsAQhL8j1VBupmnYksp9/dHz/LZEKNU+p724he44PF7Irxa4FjHaQazzZP8CWmuewNzRjQwV5n5JLMPPQ="
            ],
            "alg": "RS256"
        },
        {
            "kty": "RSA",
            "use": "sig",
            "n": "na98UqN9aFk6XVccGUF2e9_W0Q8c4N_ajip-hEk9h25ayvLzfMTEdVPuJ-7QIfG2Jh9mptaMzyEjq4W0Y7EwZz7EjZk2146OKkBvYL0mnkEBBBdjZZEChY2dvfUJJJDW3sT7gVRND6yKlKow7M1-cvRQ16-FkZ2AzR3K3rHXD76CSGAc8Qifl0TV212oW0hrCNGN-X8rZiYr7HkaLOWyT3s2KGvXAEbGyptmI2DEYZDhu5Cig10hZwPzPAgfQlJoaa2Ern2C2WYej62iUJ5q9c9Vor2xnp6MJmuXvY4DiUq05E_FE3BoUgetX1nBzM4BH-dxHRAxcWPU7HH-mjT7fQ",
            "e": "AQAB",
            "kid": "WHajrvRI1wuPgQ6JJlUF4",
            "x5t": "fXcPhcssdr97QaMpQg3tPR8Kq20",
            "x5c": [
                "MIIDBzCCAe+gAwIBAgIJOPRF+Zz8yRR3MA0GCSqGSIb3DQEBCwUAMCExHzAdBgNVBAMTFmRldi1xb3A5czlvci5hdXRoMC5jb20wHhcNMjAwMzEzMDM1NjE3WhcNMzMxMTIwMDM1NjE3WjAhMR8wHQYDVQQDExZkZXYtcW9wOXM5b3IuYXV0aDAuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAna98UqN9aFk6XVccGUF2e9/W0Q8c4N/ajip+hEk9h25ayvLzfMTEdVPuJ+7QIfG2Jh9mptaMzyEjq4W0Y7EwZz7EjZk2146OKkBvYL0mnkEBBBdjZZEChY2dvfUJJJDW3sT7gVRND6yKlKow7M1+cvRQ16+FkZ2AzR3K3rHXD76CSGAc8Qifl0TV212oW0hrCNGN+X8rZiYr7HkaLOWyT3s2KGvXAEbGyptmI2DEYZDhu5Cig10hZwPzPAgfQlJoaa2Ern2C2WYej62iUJ5q9c9Vor2xnp6MJmuXvY4DiUq05E/FE3BoUgetX1nBzM4BH+dxHRAxcWPU7HH+mjT7fQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSRECOJRsBmoj4XqH9sYYSFMSP/HDAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQELBQADggEBAECjmGA3+0UXbQrU+hjK9+fdpY3CXBU68r1Tavl545IOP1xH5nJyaDVTRB5sxUomoCDUJNIyYMbBR8syxH1dc/pw2FSWr3fOk3p7CfCgsqPTs8wCel7s+RrvvGoj3mkS1PXkDPnXmFm8+nhTX9NidraYuXyYbJ5sjxsLzoSVZzvDtDCV9obiLbSYBPIvI5bGcItJzrVygLa9ElYbzpNwHY+SmOE9VDIYMJ25VpWmyLiCqo3GHaO4wxLs7Dmz4Ff/MxTIM1GwzRB7a7Xdf4TfWGgfj597Pdmw1ITIDOY6JddDd7iOzB4tZR706V8l7KiVhvrqW3wcq0ikiPtJupfnvPU="
            ],
            "alg": "RS256"
        }
    ]
}

  1. Point keyfunc.NewDefaultCtx at any Auth0 tenant's .well-known/jwks.json.
  2. Any call to k.Keyfunc / jwt.Parse fails to validate tokens because no keys were ever successfully loaded (results in 401 responses downstream).

Expected Behavior

The JWK Set should load successfully (or at minimum, keys with a mismatched x5t should be skipped/logged as a warning rather than causing the entire refresh to fail), since Auth0 is a widely used IdP and this appears to be a common JWKS shape.

Actual Behavior

The JWK Set fails to refresh entirely. keyfunc.NewDefaultCtx returns successfully, but the background refresh never populates usable keys, so all subsequent token validation fails.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions