Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# UNRELEASED
- Improved the state validation error messages to distinguish a missing `state` parameter from a mismatched one. The end session message now notes that a provider's `end_session_endpoint` may point at a legacy or SAML single-logout endpoint, which does not echo `state`. Addresses issue #956.

# 3.0.0
- BREAKING: Updates made to support Xcode 27. ([#972](https://github.com/openid/AppAuth-iOS/pull/972), [#973](https://github.com/openid/AppAuth-iOS/pull/973))
-- Raised minimum deployment targets to iOS 15.0, macOS 12.0, tvOS 15.0 and watchOS 9.0 (minimum for Xcode 27).
Expand Down
47 changes: 35 additions & 12 deletions Sources/AppAuthCore/OIDAuthorizationService.m
Original file line number Diff line number Diff line change
Expand Up @@ -170,12 +170,22 @@ - (BOOL)resumeExternalUserAgentFlowWithURL:(NSURL *)URL error:(NSError *_Nullabl
// verifies that the state in the response matches the state in the request, or both are nil
if (!OIDIsEqualIncludingNil(_request.state, response.state)) {
NSMutableDictionary *userInfo = [query.dictionaryValue mutableCopy];
userInfo[NSLocalizedDescriptionKey] =
[NSString stringWithFormat:@"State mismatch, expecting %@ but got %@ in authorization "
"response %@",
_request.state,
response.state,
response];
if (response.state == nil) {
userInfo[NSLocalizedDescriptionKey] =
[NSString stringWithFormat:@"The authorization response is missing the state parameter, "
"expecting %@. RFC 6749 section 4.1.2 and OpenID Connect "
"Core section 3.1.2.5 require the authorization server to "
"echo the exact state value from the request. Response: %@",
_request.state,
response];
} else {
userInfo[NSLocalizedDescriptionKey] =
[NSString stringWithFormat:@"State mismatch, expecting %@ but got %@ in authorization "
"response %@",
_request.state,
response.state,
response];
}
response = nil;
responseError = [NSError errorWithDomain:OIDOAuthAuthorizationErrorDomain
code:OIDErrorCodeOAuthAuthorizationClientError
Expand Down Expand Up @@ -307,12 +317,25 @@ - (BOOL)resumeExternalUserAgentFlowWithURL:(NSURL *)URL error:(NSError *_Nullabl
// verifies that the state in the response matches the state in the request, or both are nil
if (!OIDIsEqualIncludingNil(_request.state, response.state)) {
NSMutableDictionary *userInfo = [query.dictionaryValue mutableCopy];
userInfo[NSLocalizedDescriptionKey] =
[NSString stringWithFormat:@"State mismatch, expecting %@ but got %@ in authorization "
"response %@",
_request.state,
response.state,
response];
if (response.state == nil) {
userInfo[NSLocalizedDescriptionKey] =
[NSString stringWithFormat:@"The end session response is missing the state parameter, "
"expecting %@. This may mean end_session_endpoint is not "
"an OpenID Connect RP-Initiated Logout endpoint; some "
"providers advertise a legacy or SAML single-logout "
"endpoint under that key, and those do not echo state. "
"Check end_session_endpoint in the provider's discovery "
"document. Response: %@",
_request.state,
response];
} else {
userInfo[NSLocalizedDescriptionKey] =
[NSString stringWithFormat:@"State in the end session response does not match the "
"request, expecting %@ but got %@. Response: %@",
_request.state,
response.state,
response];
}
response = nil;
responseError = [NSError errorWithDomain:OIDOAuthAuthorizationErrorDomain
code:OIDErrorCodeOAuthAuthorizationClientError
Expand Down