I’m running into an issue at this step in the iOS tutorial:
I can’t follow it exactly because I need to have compatibility with iOS 14. I’m calling the completion handler version of the function, but it doesn’t seem to be saving a token in Credential.store(). It must have to do with how I’m calling the completion handler version of the function, but I’m not sure what I’m doing wrong.
func signIn() {
Task {
WebAuthentication.shared?.signIn(from: nil, completion: { result in
switch result {
case .success(let token):
print(token.accessToken) // prints accessToken
_ = try? Credential.store(token)
print(Credential.default?.token.accessToken) // prints "nil"
updateStatus("Signed in", infoText: "", signedInStatus: true)
case .failure(let error):
showError(title: "Error: ", error: error)
}
})
}
}
Hello, thanks for your reply. When I run that, no errors are caught, the access line print out is nil
expired is false
and the id line prints out my token with user information.
It looks like everything works except accessing Credential.default.
This takes the returned credential from the store() call and then tries to retrieve the credential using the id as opposed to getting the default credential.
See here for managing Credentials. default is a convenience for the default stored Credential. You can store multiple Credentials. So it could be possible that the currently stored default does not have an access_token. If that is the case the above print debug should make sure you are trying to retrieve the Credential you just stored using it’s id.
When I create a new app in iOS15 it works on first build, but if I follow these steps, it does not store the token in default:
erase all content and settings in simulator
build
sign in
rebuild
sign in
sign out
sign in
sign out
At this point, the app displays a message about a missing id token. Sorry for the long sequence, but that is the only way I am able to recreate this issue. Eventually, while building and testing an app those steps are probably covered. Erasing all content and settings in the simulator temporarily fixes it, until all the above steps are performed.
Hi @gbe, there is definitely some subtlety to the “default” credential, which I tried to clarify in this article I wrote in the SDK documentation.
What’s probably happening is you may have multiple credentials stored, and the implicit assignment of the default credential isn’t getting set because of those previous stored credentials.
The new SDKs (okta-mobile-swift and okta-mobile-kotlin) support the storage and management of multiple credentials, to enable advanced use-cases, while the legacy OIDC SDKs only permitted one user to be logged in at a time. The default credential is intended to provide backwards compatibility, as well as a simpler workflow, for developers who only need to work with a single user (or set of tokens) at a time. It does this by auto-assigning the default credential when a new credential is stored. If the previous credential isn’t removed (e.g. using revoke or remove), the SDK won’t know that the new token is meant to replace the current default value, so it just gets stored right alongside the first.
I’d recommend using credential.revoke() instead of .remove(), because simply removing the tokens will remove them from local storage on the device, but the tokens will still be active and valid in the Authorization Server. That means if the tokens have been leaked at all, they could still be used to access resources on a server, so it’s always best to revoke them when they’re no longer needed.