Skip to content
Open
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) {
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