This is a new version of this SDK, the new pod name is OktaOidc. The old OktaAuth pod is now deprecated.
This library is a swift wrapper around the AppAuth-iOS objective-c code for communicating with Okta as an OAuth 2.0 + OpenID Connect provider, and follows current best practice for native apps using Authorization Code Flow + PKCE.
You can learn more on the Okta + iOS page in our documentation.
Table of Contents
Installing the OktaOidc SDK into your project is simple. The easiest way to include this library into your project is through CocoaPods.
You'll also need:
- An Okta account, called an organization (sign up for a free developer organization if you need one).
- An Okta Application, configured as a Native App. This is done from the Okta Developer Console and you can find instructions here. When following the wizard, use the default properties. They are designed to work with our sample applications.
Simply add the following line to your Podfile
:
pod 'OktaOidc'
Then install it into your project:
pod install
To integrate this SDK into your Xcode project using Carthage, specify it in your Cartfile:
github "okta/okta-oidc-ios"
Important: This is needed if you want to support iOS 10 and older. Starting from iOS 11 Okta uses SFAuthenticationSession API (replaced with ASWebAuthenticationSession in iOS 12) that handle redirects from browser by its own. Therefore application(,open:, options:)
won't be called during SignIn/SignOut operations.
In order to redirect back to your application from a web browser, you must specify a unique URI to your app. To do this, open Info.plist
in your application bundle and set a URL Scheme to the scheme of the redirect URI.
For example, if your Redirect URI is com.okta.example:/callback
, the URL Scheme will be com.okta.example
.
Note: Don't make redirect uri in format x.x.x.x, for example com.okta.another.example
. Safari engine will fail to redirect to your application
Next, update your AppDelegate
to include the following function to allow the redirect to occur:
// AppDelegate.swift
import OktaOidc
var oktaOidc: OktaOidc?
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool {
// oktaOidc - Configured OktaOidc instance used to start SignIn/SignOut flow.
return oktaOidc.resume(url: url, options: options)
}
To use this SDK in Objective-C project, you should do the following:
- Add
use_frameworks!
in your Pod file. - Add project setting
SWIFT_VERSION = 4.2
. To do this open Build Settings in Xcode, select Edit -> Add Build setting -> Add User-Defined Setting. SpecifySWIFT_VERSION
and4.2
as setting name and value correspondently. - Include autogenerated header
OktaOidc/OktaOidc-Swift.h
into your source code.
For an overview of this library's features and authentication flows, check out our developer docs.
You can also browse the full API reference documentation.
Before using this SDK you have to create a new object of OktaOidc
. You can instantiate OktaOidc
w/o parameters that means that SDK will use Okta.plist
for configuration values. Alternatively you can create OktaOidc
with custom configuration.
import OktaOidc
// Use the default Okta.plist configuration
let oktaOidc = OktaOidc()
// Use configuration from another resource
let config = OktaOidcConfig(/* plist */)
let config = OktaOidcConfig(/* dictionary */)
// Instantiate OktaOidc with custom configuration object
let oktaOidc = OktaOidc(configuration: config)
Need a refresh token?
A refresh token is a special token that is used to generate additional access and ID tokens. Make sure to include the offline_access
scope in your configuration to silently renew the user's session in your application!
The easiest way is to create a property list in your application's bundle. By default, this library checks for the existence of the file Okta.plist
. However any property list file can be used to create configuration object. Ensure one is created with the following fields:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>issuer</key>
<string>https://{yourOktaDomain}.com/oauth2/default</string>
<key>clientId</key>
<string>{clientId}</string>
<key>redirectUri</key>
<string>{redirectUri}</string>
<key>logoutRedirectUri</key>
<string>{logoutRedirectUri}</string>
<key>scopes</key>
<string>openid profile offline_access</string>
</dict>
</plist>
Alternatively, you can create a configuration object ( OktaOidcConfig
) from dictionary with the required values:
let configuration = OktaOidcConfig(with: [
"issuer": "https://{yourOktaDomain}/oauth2/default",
"clientId": "{clientID}",
"redirectUri": "{redirectUri}",
"logoutRedirectUri": "{logoutRedirectUri}",
"scopes": "openid profile offline_access",
// Custom parameters
"login_hint": "username@email.com"
])
Start the authorization flow by simply calling signIn
. In case of successful authorization, this operation will return valid OktaOidcStateManager
in its callback. Clients are responsible for further storage and maintenance of the manager.
oktaOidc.signInWithBrowser(from: self) { stateManager, error in
if let error = error {
// Error
return
}
// stateManager.accessToken
// stateManager.idToken
// stateManager.refreshToken
}
You can start the sign out flow by simply calling signOutFromOkta
with the appropriate OktaOidcStateManager
. This method will end the user's Okta session in the browser.
Important: This method does not clear or revoke tokens minted by Okta. Use the revoke
and clear
methods of OktaOidcStateManager
to terminate the user's local session in your application.
// Redirects to the configured 'logoutRedirectUri' specified in Okta.plist.
oktaOidc.signOutOfOkta(authStateManager, from: self) { error in
if let error = error {
// Error
return
}
}
If you already logged in to Okta and have a valid session token, you can complete authorization by calling authenticate(withSessionToken:)
. In case of successful authorization, this operation will return valid OktaOidcStateManager
in its callback. Clients are responsible for further storage and maintenance of the manager.
oktaOidc.authenticate(withSessionToken: token) { stateManager, error in
self.hideProgress()
if let error = error {
// Error
return
}
// stateManager.accessToken
// stateManager.idToken
// stateManager.refreshToken
}
Tokens are securely stored in the Keychain and can be retrieved by accessing the OktaOidcStateManager.
stateManager?.accessToken
stateManager?.idToken
stateManager?.refreshToken
User is responsible for storing OktaAuthStateManager returned by signInWithBrowser
or authenticate
operation. To store manager call the writeToSecureStorage
method:
oktaOidc.signInWithBrowser(from: self) { stateManager, error in
stateManager.writeToSecureStorage()
}
To retrieve stored manager call readFromSecureStorage(for: )
and pass here Okta configuration that corresponds to a manager you are interested in.
guard let stateManager = OktaOidcStateManager.readFromSecureStorage(for: oktaConfig) else {
// unauthenticated
}
//authenticated
// stateManager.accessToken
// stateManager.idToken
// stateManager.refreshToken
Note: In OktaOidc SDK 3.0 we added support for multiple Oauth 2.0 accounts. So developer can use Okta endpoint, social endpoint and others in one application. Therefore OktaOidcStateManager
is stored in keychain using composite key constructed based on configuration. For backward compatibility there is a method readFromSecureStorage()
that tries to read OktaOidcStateManager
stored on a legacy way, so user could retrieve previously stored OktaOidcStateManager
after switching to a newer version of SDK.
Calls the introspection endpoint to inspect the validity of the specified token.
stateManager?.introspect(token: accessToken, callback: { payload, error in
guard let isValid = payload["active"] as? Bool else {
// Error
return
}
print("Is token valid? \(isValid)")
})
Since access tokens are traditionally short-lived, you can renew expired tokens by exchanging a refresh token for new ones. See the configuration reference to ensure your app is configured properly for this flow.
stateManager?.renew { newAccessToken, error in
if let error = error else {
// Error
return
}
// renewed TokenManager
}
Calls the revocation endpoint to revoke the specified token.
stateManager?.revoke(accessToken) { response, error in
if let error = error else {
// Error
return
}
// Token was revoked
}
Calls the OpenID Connect UserInfo endpoint with the stored access token to return user claim information.
stateManager?.getUser { response, error in
if let error = error {
// Error
return
}
// JSON response
}
Removes the local authentication state by removing cached tokens in the keychain. Note: SDK deletes all keychain items accessible to an application.
stateManager.clear()
To perform an end-to-end test, update the Okta.plist
file to match your configuration as specified in the prerequisites. Next, export the following environment variables:
export USERNAME={username}
export PASSWORD={password}
export CLIENT_ID={clientId}
export ISSUER=https://{yourOktaDomain}/oauth2/default
export REDIRECT_URI={redirectUri}
export LOGOUT_REDIRECT_URI={logoutRedirectUri}
# Run E2E end Unit tests
bash ./scripts/build-and-test.sh
Note: You may need to update the emulator device to match your Xcode version