Skip to content

Commit 29b56c3

Browse files
authored
Merge pull request #28 from timhallmann/add_state_nonce_prompt
2 parents 76ae516 + cdef762 commit 29b56c3

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

src/simple_openid_connect/flows/authorization_code_flow/__init__.py

+19-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
TokenRequest,
2222
TokenSuccessResponse,
2323
)
24-
from simple_openid_connect.exceptions import AuthenticationFailedError
24+
from simple_openid_connect.exceptions import AuthenticationFailedError, ValidationError
2525

2626
logger = logging.getLogger(__name__)
2727

@@ -31,20 +31,31 @@ def start_authentication(
3131
scope: str,
3232
client_id: str,
3333
redirect_uri: str,
34+
state: Optional[str] = None,
35+
nonce: Optional[str] = None,
36+
prompt: Optional[list[str]] = None,
3437
code_challenge: Optional[str] = None,
3538
code_challenge_method: Optional[str] = None,
3639
) -> str:
3740
"""
3841
Start the authentication process by constructing an appropriate :class:`AuthenticationRequest`, serializing it and
3942
returning a which the end user now needs to visit.
4043
44+
:param state: The state intended to prevent Cross-Site Request Forgery.
45+
:param nonce: String value used to associate a Client session with an ID Token, and to mitigate replay attacks.
46+
:param prompt: Specifies whether the Authorization Server prompts the End-User for reauthentication and consent.
47+
The defined values are: "none", "login", "consent" and "select_account", multiple may be given as a list.
48+
4149
:returns: A URL to which the user agent should be redirected
4250
"""
4351
request = AuthenticationRequest(
4452
scope=scope,
4553
client_id=client_id,
4654
redirect_uri=redirect_uri,
4755
response_type="code",
56+
state=state,
57+
nonce=nonce,
58+
prompt=prompt,
4859
code_challenge=code_challenge,
4960
code_challenge_method=code_challenge_method,
5061
)
@@ -56,6 +67,7 @@ def handle_authentication_result(
5667
token_endpoint: str,
5768
client_authentication: ClientAuthenticationMethod,
5869
redirect_uri: Union[Literal["auto"], str] = "auto",
70+
state: Optional[str] = None,
5971
code_verifier: Optional[str] = None,
6072
code_challenge: Optional[str] = None,
6173
code_challenge_method: Optional[str] = None,
@@ -70,8 +82,10 @@ def handle_authentication_result(
7082
:param client_authentication: A way for the client to authenticate itself
7183
:param redirect_uri: The `redirect_uri` that was specified during the authentication initiation.
7284
If the special value `auto` is used, it is assumed that `current_url` is the that callback and it is stripped of query parameters and fragments to reproduce the originally supplied one.
85+
:param state: The `state` that was specified during the authentication initiation.
7386
7487
:raises AuthenticationFailedError: If the current url indicates an authentication failure that prevents an access token from being retrieved.
88+
:raises ValidationError: If the returned state does not match the given state.
7589
7690
:returns: The result of the token exchange
7791
"""
@@ -92,6 +106,10 @@ def handle_authentication_result(
92106
)
93107

94108
auth_response_msg = AuthenticationSuccessResponse.parse_url(str(current_furl))
109+
110+
if state != auth_response_msg.state:
111+
raise ValidationError("Returned state does not match given state.")
112+
95113
return exchange_code_for_tokens(
96114
token_endpoint=token_endpoint,
97115
authentication_response=auth_response_msg,

src/simple_openid_connect/flows/authorization_code_flow/client.py

+13
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,20 @@ def __init__(self, base_client: "OpenidClient"):
2929

3030
def start_authentication(
3131
self,
32+
state: Optional[str] = None,
33+
nonce: Optional[str] = None,
34+
prompt: Optional[list[str]] = None,
3235
code_challenge: Optional[str] = None,
3336
code_challenge_method: Optional[str] = None,
3437
) -> str:
3538
"""
3639
Start the authentication process by constructing an appropriate :class:`AuthenticationRequest`, serializing it and
3740
returning a which the end user now needs to visit.
3841
42+
:param state: The state intended to prevent Cross-Site Request Forgery.
43+
:param nonce: String value used to associate a Client session with an ID Token, and to mitigate replay attacks.
44+
:param prompt: Specifies whether the Authorization Server prompts the End-User for reauthentication and consent.
45+
The defined values are: "none", "login", "consent" and "select_account", multiple may be given as a list.
3946
:param code_challenge: The code challenge intended for use with Proof Key for Code Exchange (PKCE) [RFC7636].
4047
:param code_challenge_method: The code challenge method intended for use with Proof Key for Code Exchange (PKCE) [RFC7636], typically "S256" or "plain".
4148
@@ -55,6 +62,9 @@ def start_authentication(
5562
self._base_client.scope,
5663
self._base_client.client_auth.client_id,
5764
redirect_uri.tostr(),
65+
state=state,
66+
nonce=nonce,
67+
prompt=prompt,
5868
code_challenge=code_challenge,
5969
code_challenge_method=code_challenge_method,
6070
)
@@ -63,6 +73,7 @@ def handle_authentication_result(
6373
self,
6474
current_url: str,
6575
additional_redirect_args: Optional[Mapping[str, str]] = None,
76+
state: Optional[str] = None,
6677
code_verifier: Optional[str] = None,
6778
code_challenge: Optional[str] = None,
6879
code_challenge_method: Optional[str] = None,
@@ -74,6 +85,7 @@ def handle_authentication_result(
7485
The authentication result should be encoded into this url by the authorization server.
7586
:param additional_redirect_args: Additional URL parameters that were added to the redirect uri.
7687
They are probably still present in `current_url` but since they could be of any shape, no attempt is made here to automatically reconstruct them.
88+
:param state: The `state` that was specified during the authentication initiation.
7789
:param code_verifier: The code verifier intended for use with Proof Key for Code Exchange (PKCE) [RFC7636].
7890
:param code_challenge: The code challenge intended for use with Proof Key for Code Exchange (PKCE) [RFC7636].
7991
:param code_challenge_method: The code challenge method intended for use with Proof Key for Code Exchange (PKCE) [RFC7636], typically "S256" or "plain".
@@ -103,6 +115,7 @@ def handle_authentication_result(
103115
token_endpoint=self._base_client.provider_config.token_endpoint,
104116
client_authentication=self._base_client.client_auth,
105117
redirect_uri=redirect_uri.tostr(),
118+
state=state,
106119
code_verifier=code_verifier,
107120
code_challenge=code_challenge,
108121
code_challenge_method=code_challenge_method,

0 commit comments

Comments
 (0)