panva / openid-client

OAuth 2 / OpenID Connect Client API for JavaScript Runtimes
MIT License
1.83k stars 392 forks source link

Revocation: OPError: expected 200 OK, got: 204 No Content #482

Closed frcouceiro closed 2 years ago

frcouceiro commented 2 years ago

Describe the bug I am testing both the client and node-oidc-provider and when issuing a revoke request I get the following error:

OPError: expected 200 OK, got: 204 No Content
at processResponse ([/node_modules/openid-client/lib/helpers/process_response.js:41:11]())
at Client.revoke ([/node_modules/openid-client/lib/client.js:1403:5]())

Turns out the provider is responding with status 204 as opposed to what the client expects (status 200). I guess I have two alternatives:

  1. Make the provider return a 200 (how?)
  2. Make the client expect a 204 instead (processResponse seems to allow us to specify a statusCode).

To Reproduce Issuer and Client configuration: (inline or gist) - Don't forget to redact your secrets.

// Issuer configuration (issuer.metadata) and how it is constructed -> **discovery**
{
    "claim_types_supported": ["normal"],
    "claims_parameter_supported": false,
    "grant_types_supported": ["implicit", "authorization_code", "refresh_token"],
    "request_parameter_supported": false,
    "request_uri_parameter_supported": true,
    "require_request_uri_registration": true,
    "response_modes_supported": ["form_post", "fragment", "query"],
    "token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_jwt", "client_secret_post", "private_key_jwt", "none"],
    "authorization_endpoint": "http://localhost:3000/auth",
    "claims_supported": ["sub", "name", "address", "email", "email_verified", "phone_number", "phone_number_verified", "birthdate", "family_name", "gender", "given_name", "locale", "middle_name", "nickname", "picture", "preferred_username", "profile", "updated_at", "website", "zoneinfo", "sid", "auth_time", "iss"],
    "code_challenge_methods_supported": ["S256"],
    "end_session_endpoint": "http://localhost:3000/session/end",
    "id_token_signing_alg_values_supported": ["EdDSA", "ES256", "PS256", "RS256"],
    "issuer": "http://localhost:3000",
    "jwks_uri": "http://localhost:3000/jwks",
    "registration_endpoint": "http://localhost:3000/reg",
    "response_types_supported": ["code id_token", "code", "id_token", "none"],
    "scopes_supported": ["openid", "offline_access", "address", "email", "phone", "profile"],
    "subject_types_supported": ["public"],
    "token_endpoint_auth_signing_alg_values_supported": ["HS256", "RS256", "PS256", "ES256", "EdDSA"],
    "token_endpoint": "http://localhost:3000/token",
    "request_object_signing_alg_values_supported": ["HS256", "RS256", "PS256", "ES256", "EdDSA"],
    "userinfo_endpoint": "http://localhost:3000/me",
    "introspection_endpoint": "http://localhost:3000/token/introspection",
    "introspection_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_jwt", "client_secret_post", "private_key_jwt", "none"],
    "introspection_endpoint_auth_signing_alg_values_supported": ["HS256", "RS256", "PS256", "ES256", "EdDSA"],
    "revocation_endpoint": "http://localhost:3000/token/revocation",
    "revocation_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_jwt", "client_secret_post", "private_key_jwt", "none"],
    "revocation_endpoint_auth_signing_alg_values_supported": ["HS256", "RS256", "PS256", "ES256", "EdDSA"]
}
// Client configuration (client.metadata) and how it is constructed -> **manual**
{
    "grant_types": ["authorization_code"],
    "id_token_signed_response_alg": "RS256",
    "authorization_signed_response_alg": "RS256",
    "response_types": ["code"],
    "token_endpoint_auth_method": "client_secret_basic",
    "client_id": "<redacted>",
    "client_secret": "<redacted>",
    "redirect_uris": ["http://localhost:3001/cb"],
    "introspection_endpoint_auth_method": "client_secret_basic",
    "revocation_endpoint_auth_method": "client_secret_basic"
}

Steps to reproduce the behaviour:

  1. Connect with a client and save the refresh token
  2. Issue a revoke token request by supplying the refresh token

Expected behaviour

I tested option 2. above and it does work however as I am just starting to get my hands on both projects and I am not sure these are the only possibilities or even if they adhere to these projects principles. I was hoping to get an answer on that and I can submit a PR with option 2. if you see fit 👍

Thank you for the great work!

Environment:

Additional context Add any other context about the problem here.

panva commented 2 years ago

The client is exhibiting correct behaviour, 200 OK is the expected response. PR not needed. The provider, from looking at the code, the tests, and even testing my deployment, returns a 200 OK, not 204. PR not needed.

➜  curl -iX POST https://op.panva.cz/token/revocation -d 'client_id=bu7K-J98Ccwmca2-RcXT9&token=foo'
HTTP/2 200
date: Fri, 08 Apr 2022 15:01:35 GMT
content-length: 0

Maybe there's something at play in your deployment of the provider, I don't know.

Please create and share a minimal reproduction code for the provider application that i can easilly run and reproduce locally if you'd like me to look into it, as-is, I cannot reproduce the reported provider behaviour.

frcouceiro commented 2 years ago

Thank you for the quick response.

Naturally you are right. I can now see provider response being a 200 OK, somehow when debugging openid-client code response object I do always get a 204. I am using serverless-offline + serverless-http plugin and I am starting to think it may be related. Will test by using express server directly. If I end up with the same issue I will submit a minimal reproducible project so we can further look into it. Cheers