We are integrating Okta into our mobile applications. We are following resource owner password flow and okta sdk (GitHub - okta/okta-oidc-ios: Okta with AppAuth).
In the documentation (readme) it says that If using the Resource Owner Password Grant, you must specify the clientSecret in Okta.plist. But it also mention that IMPORTANT: It is strongly discouraged to store a clientSecret on a distributed app. Please refer to OAuth 2.0 for Native Apps for more information.
So how can we set/update the clientSecret from the code (programmatically)? I could not find any method to set clientSecret in the SDK.
There is no way to set the client secret programmatically. Your options for using the Okta AppAuth SDK are:
- Use the Resource Owner Password grant and store the client secret in Okta.plist, or
- Use the Authorization Code grant (
.login().start(view: ...
)
The latter is more secure and is recommended. However, if you need a fully-native login experience, the Resource Owner Password grant is the only way to go.
Thanks for your answer. We are following Resource Owner Password and using SDK (.login().start(view: …) to get the accesstoken and refresh token. So when the access token is expired how can we get a new access token? Is there any SDK methods for that purpose? I saw one method OktaAuth.refresh(), but I could not find any examples for that. Could you please help me on this?
OktaAuth.refresh()
should do it. See this function in the example app: https://github.com/okta/okta-sdk-appauth-ios/blob/master/Example/Okta/ViewController.swift#L23
What happens when you call refresh()
? Are you requesting the offline_access
scope during the initial request?
I am getting following error when I call the OktaAuth.refresh(). But my login call is working fine and I am able to get accesstoken and refreshToken etc after login success. We are following Resource Owner Password and using Okta SDK.
2017-12-20 16:37:25.778316-0800 OktaSample[10452:275416] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil’
*** First throw call stack:
(
0 CoreFoundation 0x0000000112f2f1cb __exceptionPreprocess + 171
1 libobjc.A.dylib 0x000000010f57df41 objc_exception_throw + 48
2 CoreFoundation 0x0000000112f6ee8c _CFThrowFormattedException + 194
3 CoreFoundation 0x0000000112e5e6f1 -[__NSArrayM insertObject:atIndex:] + 1233
4 AppAuth 0x000000010eee4d23 -[OIDURLQueryComponent addParameter:value:] + 259
5 AppAuth 0x000000010eee2759 -[OIDTokenRequest URLRequest] + 809
6 AppAuth 0x000000010eed1eac +[OIDAuthorizationService performTokenRequest:callback:] + 92
7 AppAuth 0x000000010eed8357 -[OIDAuthState performActionWithFreshTokens:additionalRefreshParameters:] + 1671
8 AppAuth 0x000000010eed7cb0 -[OIDAuthState performActionWithFreshTokens:] + 64
9 OktaAuth 0x000000010ef1a623 _T08OktaAuth7refreshyyF + 659
10 OktaSample 0x000000010ebd81fc _T010OktaSample14ViewControllerC9btnRefrshyypF + 252
11 OktaSample 0x000000010ebd8d88 _T010OktaSample14ViewControllerC9btnRefrshyypFTo + 72
12 UIKit 0x000000010ff9cec9 -[UIApplication sendAction:to:from:forEvent:] + 83
13 UIKit 0x000000011011a1f6 -[UIControl sendAction:to:forEvent:] + 67
14 UIKit 0x000000011011a513 -[UIControl _sendActionsForEvents:withEvent:] + 450
15 UIKit 0x0000000110119440 -[UIControl touchesEnded:withEvent:] + 618
16 UIKit 0x0000000110012b1b -[UIWindow _sendTouchesForEvent:] + 2807
17 UIKit 0x000000011001423e -[UIWindow sendEvent:] + 4124
18 UIKit 0x000000010ffb7d96 -[UIApplication sendEvent:] + 352
19 UIKit 0x00000001108f9fce __dispatchPreprocessedEventFromEventQueue + 2809
20 UIKit 0x00000001108fcc23 __handleEventQueueInternal + 5957
21 CoreFoundation 0x0000000112ed22b1 CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 17
22 CoreFoundation 0x0000000112f71d31 __CFRunLoopDoSource0 + 81
23 CoreFoundation 0x0000000112eb6c19 __CFRunLoopDoSources0 + 185
24 CoreFoundation 0x0000000112eb61ff __CFRunLoopRun + 1279
25 CoreFoundation 0x0000000112eb5a89 CFRunLoopRunSpecific + 409
26 GraphicsServices 0x00000001192d19c6 GSEventRunModal + 62
27 UIKit 0x000000010ff9b23c UIApplicationMain + 159
28 OktaSample 0x000000010ebdb737 main + 55
29 libdyld.dylib 0x0000000117321d81 start + 1
30 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
In My Okta.plist file I have given that offline_access
<key>scopes</key>
<array>
<string>offline_access</string>
<string>openid</string>
<string>profile</string>
</array>
Can you double-check that you are receiving a refresh token? Make sure that the application config allows a refresh token:
If the response coming back from the Resource Owner Password grant includes a refresh token, it sounds like a bug in the iOS SDK. I’d recommend filing an issue here: https://github.com/okta/okta-sdk-appauth-ios/issues
Ping @jmelberg
I am receiving refresh token in .login("user@example.com", password: “password”)
.start(withPListConfig: “Okta”, view:self) in for Resource Owner Password flow. But when I try to call the OktaAuth.refresh() method, I am getting the crash as I said above.
@nate.barbettini & @shihabkb: This is a bug with how the authentication state is stored in the Okta AppAuth wrapper.
There is a very good chance we will be removing support for the Resource Owner Password OAuth 2.0 flow in the future, so I am not sure when/if this will be fixed.
@shihabkb: Is there a reason you are using this flow as opposed to the recommended Authorization Code Flow + PKCE? The Resource Owner Password flow is for private clients that can protect a client_secret
. Native applications are to be treated as public clients. This is a less secure method, as the client_secret
can be reverse engineered from the distributed app. See OAuth 2.0 for Native Apps for more information.