Closed marcomuser closed 5 months ago
We could probably add an API that parses the well known config, but I'm not sure how it could automatically configure PKCE since that's defined within createAuthorizationURL()
instead of the entire OAuth2Client
class
Yes, that's true. What was the reason to export a separate function createAuthorizationURL instead of exposing it as a class method?
It is a class method?
Yeaaaah, sorry about that. I shouldn't post from my phone late in the evening. 😆 Was thinking of something else.
We could focus on automatically discovering and configuring the /token
and /authorize
endpoints via the .well-known discovery endpoint IF a user instantiates the client without token and authorize endpoints BUT provides the discovery endpoint. This is how it works in the oauth2-client lib. The createAuthorizationURL method would still expect its arguments as-is for PKCE. The benefit would be that the client would continue to function just fine if the oAuth2 server decided - for whatever reason - to change the urls of either token or authorize endpoint.
Let me know if I'm still missing your point. ;-) Very well possible.
Sorry, got Oslo and Arctic providers mixed up.
Honestly though, If you know the well known endpoint, I feel it's easier if you just copy paste the authorization and token endpoint. It would be nice if Oslo could parse the well known config and magically update the types to require certain items, but I don't think that would be realistic.
What do you mean by magically updating the types? If you are talking about the client instantiation, this could simply be handled by a union type if the arguments were all passed in a single object:
new OAuth2Client({
clientId,
authorizeEndpoint
tokenEndpoint,
redirectURI
});
OR
new OAuth2Client({
clientId,
discoveryEndpoint,
redirectURI
});
The Options type would look something like this:
type OAuth2ClientOptions = {
clientId: string,
authorizeEndpoint: string,
tokenEndpoint: string,
redirectURI: string
} | {
clientId: string,
discoveryEndpoint: string,
redirectURI: string
}
It would force the user to either be explicit with the endpoints or let the client handle it via parsing the well-known config.
Having said that, I recognize that the additional fetching logic and parsing of the well-known config adds quite a bit of complexity. The benefit as said earlier is that it allows OAuth Providers to change the endpoints without breaking clients downstream. If you decide that that is not worth the added complexity I'm absolutely fine with that! This library is fantastic already as-is so thanks again for it!
By magically, I mean like requiring PKCE for providers that support it etc.
I'm a little bit shocked how this proposal/disussion was shutdown here.
First I've setup my Keycloak to use PKCE and checked the /.well-known/openid-configuration
for my realm and as described in https://www.rfc-editor.org/rfc/rfc8414.html the metadata name code_challenge_methods_supported
can be used to identify which challenage method is supported by PKCE so PKCE is enabled and can be used for configuration.
Here a corresponding setup:
{ "issuer": "https://auth.local.str84ward.net/realms/master", "authorization_endpoint": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/auth", "token_endpoint": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/token", "introspection_endpoint": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/token/introspect", "userinfo_endpoint": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/userinfo", "end_session_endpoint": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/logout", "frontchannel_logout_session_supported": true, "frontchannel_logout_supported": true, "jwks_uri": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/certs", "check_session_iframe": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/login-status-iframe.html", "grant_types_supported": [ "authorization_code", "implicit", "refresh_token", "password", "client_credentials", "urn:openid:params:grant-type:ciba", "urn:ietf:params:oauth:grant-type:device_code" ], "acr_values_supported": [ "0", "1" ], "response_types_supported": [ "code", "none", "id_token", "token", "id_token token", "code id_token", "code token", "code id_token token" ], "subject_types_supported": [ "public", "pairwise" ], "id_token_signing_alg_values_supported": [ "PS384", "RS384", "EdDSA", "ES384", "HS256", "HS512", "ES256", "RS256", "HS384", "ES512", "PS256", "PS512", "RS512" ], "id_token_encryption_alg_values_supported": [ "RSA-OAEP", "RSA-OAEP-256", "RSA1_5" ], "id_token_encryption_enc_values_supported": [ "A256GCM", "A192GCM", "A128GCM", "A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512" ], "userinfo_signing_alg_values_supported": [ "PS384", "RS384", "EdDSA", "ES384", "HS256", "HS512", "ES256", "RS256", "HS384", "ES512", "PS256", "PS512", "RS512", "none" ], "userinfo_encryption_alg_values_supported": [ "RSA-OAEP", "RSA-OAEP-256", "RSA1_5" ], "userinfo_encryption_enc_values_supported": [ "A256GCM", "A192GCM", "A128GCM", "A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512" ], "request_object_signing_alg_values_supported": [ "PS384", "RS384", "EdDSA", "ES384", "HS256", "HS512", "ES256", "RS256", "HS384", "ES512", "PS256", "PS512", "RS512", "none" ], "request_object_encryption_alg_values_supported": [ "RSA-OAEP", "RSA-OAEP-256", "RSA1_5" ], "request_object_encryption_enc_values_supported": [ "A256GCM", "A192GCM", "A128GCM", "A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512" ], "response_modes_supported": [ "query", "fragment", "form_post", "query.jwt", "fragment.jwt", "form_post.jwt", "jwt" ], "registration_endpoint": "https://auth.local.str84ward.net/realms/master/clients-registrations/openid-connect", "token_endpoint_auth_methods_supported": [ "private_key_jwt", "client_secret_basic", "client_secret_post", "tls_client_auth", "client_secret_jwt" ], "token_endpoint_auth_signing_alg_values_supported": [ "PS384", "RS384", "EdDSA", "ES384", "HS256", "HS512", "ES256", "RS256", "HS384", "ES512", "PS256", "PS512", "RS512" ], "introspection_endpoint_auth_methods_supported": [ "private_key_jwt", "client_secret_basic", "client_secret_post", "tls_client_auth", "client_secret_jwt" ], "introspection_endpoint_auth_signing_alg_values_supported": [ "PS384", "RS384", "EdDSA", "ES384", "HS256", "HS512", "ES256", "RS256", "HS384", "ES512", "PS256", "PS512", "RS512" ], "authorization_signing_alg_values_supported": [ "PS384", "RS384", "EdDSA", "ES384", "HS256", "HS512", "ES256", "RS256", "HS384", "ES512", "PS256", "PS512", "RS512" ], "authorization_encryption_alg_values_supported": [ "RSA-OAEP", "RSA-OAEP-256", "RSA1_5" ], "authorization_encryption_enc_values_supported": [ "A256GCM", "A192GCM", "A128GCM", "A128CBC-HS256", "A192CBC-HS384", "A256CBC-HS512" ], "claims_supported": [ "aud", "sub", "iss", "auth_time", "name", "given_name", "family_name", "preferred_username", "email", "acr" ], "claim_types_supported": [ "normal" ], "claims_parameter_supported": true, "scopes_supported": [ "openid", "address", "acr", "profile", "offline_access", "microprofile-jwt", "phone", "roles", "web-origins", "email" ], "request_parameter_supported": true, "request_uri_parameter_supported": true, "require_request_uri_registration": true, "code_challenge_methods_supported": [ "plain", "S256" ], "tls_client_certificate_bound_access_tokens": true, "revocation_endpoint": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/revoke", "revocation_endpoint_auth_methods_supported": [ "private_key_jwt", "client_secret_basic", "client_secret_post", "tls_client_auth", "client_secret_jwt" ], "revocation_endpoint_auth_signing_alg_values_supported": [ "PS384", "RS384", "EdDSA", "ES384", "HS256", "HS512", "ES256", "RS256", "HS384", "ES512", "PS256", "PS512", "RS512" ], "backchannel_logout_supported": true, "backchannel_logout_session_supported": true, "device_authorization_endpoint": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/auth/device", "backchannel_token_delivery_modes_supported": [ "poll", "ping" ], "backchannel_authentication_endpoint": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/ext/ciba/auth", "backchannel_authentication_request_signing_alg_values_supported": [ "PS384", "RS384", "EdDSA", "ES384", "ES256", "RS256", "ES512", "PS256", "PS512", "RS512" ], "require_pushed_authorization_requests": false, "pushed_authorization_request_endpoint": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/ext/par/request", "mtls_endpoint_aliases": { "token_endpoint": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/token", "revocation_endpoint": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/revoke", "introspection_endpoint": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/token/introspect", "device_authorization_endpoint": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/auth/device", "registration_endpoint": "https://auth.local.str84ward.net/realms/master/clients-registrations/openid-connect", "userinfo_endpoint": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/userinfo", "pushed_authorization_request_endpoint": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/ext/par/request", "backchannel_authentication_endpoint": "https://auth.local.str84ward.net/realms/master/protocol/openid-connect/ext/ciba/auth" }, "authorization_response_iss_parameter_supported": true }
First of all, thanks for this fantastic library! It would be great if one could only specify the .well-known discovery endpoint pointing to the server's metadata document (https://datatracker.ietf.org/doc/html/rfc8414) when instantiating the OAuth2Client and let it figure out the authorizeEndpoint and the tokenEndpoint automatically when sending requests.