Owner password flow using OIDTokenRequest crashes on token refresh
We support both Owner Password Flow, along with Authorization Code flow. I've wrapped our request layer with authState.performAction(freshTokens:). However, because I use OIDTokenRequest directly for the password flow, and call OIDAuthorizationService.perform(_: OIDTokenRequest, callback: OIDTokenCallback), AppAuth crashes in OIDTokenRequest.m on [bodyParameters addParameter:kClientIDKey value:_clientID]; since _clientID is nil.
Am I doing something wrong or not setting something I should be? Is password flow not officially supported?
Here's my password flow code snippet:
// Log in with username/pwd
OIDAuthorizationService.discoverConfiguration(forIssuer: issuer) { [weak self] configuration, error in
guard let self = self, let config = configuration else {
completion(.failure(AppAuthError.invalid))
return
}
let request = OIDTokenRequest(configuration: config,
grantType: OIDGrantTypePassword,
authorizationCode: nil,
redirectURL: redirectURL,
clientID: clientID,
clientSecret: nil,
scope: OIDScopeOpenID,
refreshToken: self.authState?.lastTokenResponse?.refreshToken,
codeVerifier: nil,
additionalParameters: ["username": username,
"password": password])
OIDAuthorizationService.perform(request) { [weak self] tokenResponse, error in
guard let self = self else {
completion(.failure(AppAuthError.invalid))
return
}
if let tokenResponse = tokenResponse {
self.authState = OIDAuthState(authorizationResponse: nil,
tokenResponse: tokenResponse,
registrationResponse: nil)
...
// continue on doing things
Try to set redirectURL: nil and check. Also check your clientID should be non nil.
Following up with my workaround on this:
OIDAuthorizationService.perform(request) { [weak self] tokenResponse, error in
guard let self = self else {
return
}
if let tokenResponse = tokenResponse {
// Password flows using `OIDTokenRequest` don't ever produce an `OIDAuthorizationResponse`, so lets "fake" one
// to prevent the `AppAuth` library from crashing when accessing a nil `client_id` query parameter when the
// token expires and the library refreshes the token.
let authResponse = OIDAuthorizationResponse(request: self.createAuthorizationRequest(with: config),
parameters: [String: NSCopying & NSObject]())
self.authState = OIDAuthState(authorizationResponse: authResponse,
tokenResponse: tokenResponse,
registrationResponse: nil)
} else {
...
}
...
}