diff --git a/authentik/providers/oauth2/constants.py b/authentik/providers/oauth2/constants.py index 5228b0fed..81460b707 100644 --- a/authentik/providers/oauth2/constants.py +++ b/authentik/providers/oauth2/constants.py @@ -19,6 +19,11 @@ SCOPE_OPENID = "openid" SCOPE_OPENID_PROFILE = "profile" SCOPE_OPENID_EMAIL = "email" +# https://www.iana.org/assignments/oauth-parameters/\ +# oauth-parameters.xhtml#pkce-code-challenge-method +PKCE_METHOD_PLAIN = "plain" +PKCE_METHOD_S256 = "S256" + TOKEN_TYPE = "Bearer" # nosec SCOPE_AUTHENTIK_API = "goauthentik.io/api" diff --git a/authentik/providers/oauth2/views/authorize.py b/authentik/providers/oauth2/views/authorize.py index 26f664d86..fd3851285 100644 --- a/authentik/providers/oauth2/views/authorize.py +++ b/authentik/providers/oauth2/views/authorize.py @@ -35,6 +35,8 @@ from authentik.lib.views import bad_request_message from authentik.policies.types import PolicyRequest from authentik.policies.views import PolicyAccessView, RequestValidationError from authentik.providers.oauth2.constants import ( + PKCE_METHOD_PLAIN, + PKCE_METHOD_S256, PROMPT_CONSENT, PROMPT_LOGIN, PROMPT_NONE, @@ -254,7 +256,10 @@ class OAuthAuthorizationParams: def check_code_challenge(self): """PKCE validation of the transformation method.""" - if self.code_challenge and self.code_challenge_method not in ["plain", "S256"]: + if self.code_challenge and self.code_challenge_method not in [ + PKCE_METHOD_PLAIN, + PKCE_METHOD_S256, + ]: raise AuthorizeError( self.redirect_uri, "invalid_request", diff --git a/authentik/providers/oauth2/views/provider.py b/authentik/providers/oauth2/views/provider.py index 001f7a3fd..ab6fbc328 100644 --- a/authentik/providers/oauth2/views/provider.py +++ b/authentik/providers/oauth2/views/provider.py @@ -17,6 +17,8 @@ from authentik.providers.oauth2.constants import ( GRANT_TYPE_IMPLICIT, GRANT_TYPE_PASSWORD, GRANT_TYPE_REFRESH_TOKEN, + PKCE_METHOD_PLAIN, + PKCE_METHOD_S256, SCOPE_OPENID, ) from authentik.providers.oauth2.models import ( @@ -109,6 +111,7 @@ class ProviderInfoView(View): "request_parameter_supported": False, "claims_supported": self.get_claims(provider), "claims_parameter_supported": False, + "code_challenge_methods_supported": [PKCE_METHOD_PLAIN, PKCE_METHOD_S256], } def get_claims(self, provider: OAuth2Provider) -> list[str]: diff --git a/authentik/providers/oauth2/views/token.py b/authentik/providers/oauth2/views/token.py index 8a8be7f05..0e4a50238 100644 --- a/authentik/providers/oauth2/views/token.py +++ b/authentik/providers/oauth2/views/token.py @@ -39,6 +39,7 @@ from authentik.providers.oauth2.constants import ( GRANT_TYPE_DEVICE_CODE, GRANT_TYPE_PASSWORD, GRANT_TYPE_REFRESH_TOKEN, + PKCE_METHOD_S256, TOKEN_TYPE, ) from authentik.providers.oauth2.errors import DeviceCodeError, TokenError, UserAuthError @@ -221,7 +222,7 @@ class TokenParams: # Validate PKCE parameters. if self.code_verifier: - if self.authorization_code.code_challenge_method == "S256": + if self.authorization_code.code_challenge_method == PKCE_METHOD_S256: new_code_challenge = ( urlsafe_b64encode(sha256(self.code_verifier.encode("ascii")).digest()) .decode("utf-8")