diff --git a/packages/@okta/vuepress-site/.vuepress/public/img/mobile-sdk/mobile-idx-basic-objects.png b/packages/@okta/vuepress-site/.vuepress/public/img/mobile-sdk/mobile-idx-basic-objects.png
old mode 100644
new mode 100755
index 969d05a9143..204f4ac9c17
Binary files a/packages/@okta/vuepress-site/.vuepress/public/img/mobile-sdk/mobile-idx-basic-objects.png and b/packages/@okta/vuepress-site/.vuepress/public/img/mobile-sdk/mobile-idx-basic-objects.png differ
diff --git a/packages/@okta/vuepress-site/.vuepress/public/img/mobile-sdk/mobile-idx-objects-and-flow-kotlin.png b/packages/@okta/vuepress-site/.vuepress/public/img/mobile-sdk/mobile-idx-objects-and-flow-kotlin.png
new file mode 100644
index 00000000000..a8e5a8ab9dd
Binary files /dev/null and b/packages/@okta/vuepress-site/.vuepress/public/img/mobile-sdk/mobile-idx-objects-and-flow-kotlin.png differ
diff --git a/packages/@okta/vuepress-site/.vuepress/public/img/mobile-sdk/mobile-idx-objects-and-flow-swift.png b/packages/@okta/vuepress-site/.vuepress/public/img/mobile-sdk/mobile-idx-objects-and-flow-swift.png
new file mode 100755
index 00000000000..62e70ecf2c0
Binary files /dev/null and b/packages/@okta/vuepress-site/.vuepress/public/img/mobile-sdk/mobile-idx-objects-and-flow-swift.png differ
diff --git a/packages/@okta/vuepress-site/.vuepress/public/img/mobile-sdk/mobile-idx-objects-and-flow.png b/packages/@okta/vuepress-site/.vuepress/public/img/mobile-sdk/mobile-idx-objects-and-flow.png
deleted file mode 100644
index b69a7372381..00000000000
Binary files a/packages/@okta/vuepress-site/.vuepress/public/img/mobile-sdk/mobile-idx-objects-and-flow.png and /dev/null differ
diff --git a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/gettingatoken.md b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/gettingatoken.md
index 47739544ba4..efac055ac15 100644
--- a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/gettingatoken.md
+++ b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/gettingatoken.md
@@ -1,20 +1,23 @@
```kotlin
+import com.okta.authfoundation.client.OidcClientResult
+import com.okta.authfoundationbootstrap.CredentialBootstrap
import com.okta.idx.kotlin.dto.IdxRemediation.Type.ISSUE
import com.okta.idx.kotlin.dto.IdxResponse
-import com.okta.idx.kotlin.client.IdxClientResult
private suspend fun handleResponse(response: IdxResponse) {
// Check if the sign-in flow is successful.
if (response.isLoginSuccessful) {
- // Exchange the sign-in session token for a connection token.
- when (val exchangeCodesResult = client?.exchangeInteractionCodeForTokens(response.remediations[ISSUE]!!)) {
- is IdxClientResult.Error -> {
+ // Exchange the sign-in session token for a token.
+ when (val exchangeCodesResult =
+ flow?.exchangeInteractionCodeForTokens(response.remediations[ISSUE]!!))
+ {
+ is OidcClientResult.Error -> {
// Handle the error.
}
- is IdxClientResult.Success -> {
+ is OidcClientResult.Success -> {
// Handle a successful sign-in flow.
- // The token is in `exchangeCodesResult.result`.
// Store it securely for future use.
+ CredentialBootstrap.defaultCredential().storeToken(exchangeCodesResult.result)
}
else -> {
// Handle the error.
diff --git a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/initializeflow.md b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/initializeflow.md
new file mode 100644
index 00000000000..7244bfd7e67
--- /dev/null
+++ b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/initializeflow.md
@@ -0,0 +1,54 @@
+
+The following example loads the configuration values for the flow from a property file in your project.
+
+First, create a property file, for example, `okta.properties` in the project root. Add the values for your Okta app integration to the file.
+
+```properties
+discoveryUrl=https://{yourIssuerUrl}/oauth2/default/.well-known/openid-configuration
+clientId={yourClientId}
+redirectUri=com.okta.sample.android:/login
+```
+
+Add this configuration to your `app/build.gradle` to make the properties available in the build configuration:
+
+```gradle
+def oktaProperties = new Properties()
+rootProject.file("okta.properties").withInputStream { oktaProperties.load(it) }
+
+defaultConfig {
+ ...
+
+ buildConfigField "String", 'DISCOVERY_URL', "\"${oktaProperties.getProperty('discoveryUrl')}\""
+ buildConfigField "String", 'CLIENT_ID', "\"${oktaProperties.getProperty('clientId')}\""
+ buildConfigField "String", 'REDIRECT_URI', "\"${oktaProperties.getProperty('redirectUri')}\""
+
+ ...
+}
+```
+
+In your `Application` subclass, initialize `AuthFoundationBootstrap` from the `BuildConfig` by calling `initializeAuthFoundation` from `onCreate`.
+
+```kotlin
+import com.okta.android.samples.authenticator.BuildConfig
+import com.okta.authfoundation.AuthFoundationDefaults
+import com.okta.authfoundation.client.OidcClient
+import com.okta.authfoundation.client.OidcConfiguration
+import com.okta.authfoundation.client.SharedPreferencesCache
+import com.okta.authfoundation.credential.CredentialDataSource.Companion.createCredentialDataSource
+import com.okta.authfoundationbootstrap.CredentialBootstrap
+import okhttp3.HttpUrl.Companion.toHttpUrl
+
+fun initializeAuthFoundation() {
+ // Initializes Auth Foundation and Credential Bootstrap classes.
+ AuthFoundationDefaults.cache = SharedPreferencesCache.create(this)
+ val oidcConfiguration = OidcConfiguration(
+ clientId = BuildConfig.CLIENT_ID,
+ defaultScope = "openid email profile offline_access",
+ )
+ val client = OidcClient.createFromDiscoveryUrl(
+ oidcConfiguration,
+ BuildConfig.DISCOVERY_URL.toHttpUrl(),
+ )
+ CredentialBootstrap.initialize(client.createCredentialDataSource(this))
+}
+```
diff --git a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/initializingsdksession.md b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/initializingsdksession.md
index b2f74991814..f31099b8b1f 100644
--- a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/initializingsdksession.md
+++ b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/initializingsdksession.md
@@ -1,26 +1,35 @@
-This example creates the client in the viewmodel `launch` coroutine. Start by calling `IdxClient.start()` and on success, request the first response by calling `resume()` on the result.
+This example creates the flow in the viewmodel `launch` coroutine. Start by calling `CredentialBootstrap.oidcClient.createInteractionCodeFlow` and on success, request the first response by calling `resume` on the result.
```kotlin
-@Volatile
-private var client: IdxClient? = null
+import com.okta.authfoundation.client.OidcClientResult
+import com.okta.authfoundationbootstrap.CredentialBootstrap
+import com.okta.idx.kotlin.client.InteractionCodeFlow
+import com.okta.idx.kotlin.client.InteractionCodeFlow.Companion.createInteractionCodeFlow
+import com.okta.idx.kotlin.dto.IdxResponse
+@Volatile
+private var flow: InteractionCodeFlow? = null
private fun createClient() {
viewModelScope.launch {
- // Initialize the SDK client and start sign-in flow.
- when (val clientResult = IdxClient.start(OktaIdxClientConfigurationProvider.get())) {
- is IdxClientResult.Error -> {
+ // Initialize the SDK and start sign-in flow.
+ when (
+ val clientResult = CredentialBootstrap.oidcClient.createInteractionCodeFlow(
+ redirectUrl = BuildConfig.REDIRECT_URI,
+ )
+ ) {
+ is OidcClientResult.Error -> {
// Handle the error.
}
- is IdxClientResult.Success -> {
- client = clientResult.result
+ is OidcClientResult.Success -> {
+ flow = clientResult.result
// Request the first response by calling resume and handle the asynchronous response.
when (val resumeResult = clientResult.result.resume()) {
- is IdxClientResult.Error -> {
+ is OidcClientResult.Error -> {
// Handle the error.
}
- is IdxClientResult.Success -> handleResponse(resumeResult.result)
+ is OidcClientResult.Success -> handleResponse(resumeResult.result)
}
}
}
diff --git a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/loadingaconfiguration.md b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/loadingaconfiguration.md
deleted file mode 100644
index 3e7cc859115..00000000000
--- a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/loadingaconfiguration.md
+++ /dev/null
@@ -1,48 +0,0 @@
-
-Create a configuration by calling `IdxClientConfiguration`. This code shows loading the values from a property file in your project.
-
-First, create a property file, for example, `okta.properties` in the project root. Add the values for your Okta application integration to the file.
-
-```
-issuer={yourIssuerUrl}
-clientId={yourClientId}
-scopes="openid","email","profile","offline_access"
-redirectUri=com.okta.sample.android:/login
-```
-
-Add this configuration to the `defaultConfig` section of your `app/build.gradle` to make the properties available in the build configuration:
-
-```gradle
-defaultConfig {
- ...
-
- buildConfigField "String", 'ISSUER', "\"${oktaProperties.getProperty('issuer')}\""
- buildConfigField "String", 'CLIENT_ID', "\"${oktaProperties.getProperty('clientId')}\""
- buildConfigField "String[]", 'SCOPES', "{${oktaProperties.getProperty('scopes')}}"
- buildConfigField "String", 'REDIRECT_URI', "\"${oktaProperties.getProperty('redirectUri')}\""
-
- ...
-}
-```
-
-Create an `OktaIdxClientConfigurationProvider` class that returns an `IdxClientConfiguration` from the `BuildConfig`.
-
-```kotlin
-import com.okta.android.samples.authenticator.BuildConfig
-import com.okta.idx.kotlin.client.IdxClientConfiguration
-import okhttp3.HttpUrl.Companion.toHttpUrl
-
-/**
- * Return an Okta org configuration from the build configuration.
- */
-internal object OktaIdxClientConfigurationProvider {
- fun get(): IdxClientConfiguration {
- return IdxClientConfiguration(
- issuer = BuildConfig.ISSUER.toHttpUrl(),
- clientId = BuildConfig.CLIENT_ID,
- scopes = BuildConfig.SCOPES.toSet(),
- redirectUri = BuildConfig.REDIRECT_URI,
- )
- }
-}
-```
diff --git a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/objectsandflow.md b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/objectsandflow.md
new file mode 100644
index 00000000000..e6bcaf31f25
--- /dev/null
+++ b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/objectsandflow.md
@@ -0,0 +1,17 @@
+
+
+!["A diagram that shows the main objects associated with each step in the sign-in flow."](/img/mobile-sdk/mobile-idx-objects-and-flow-kotlin.png)
+
+
+
+The main objects associated with each step in the flow are:
+
+| Sign-in step | Objects |
+| :--------------------------------- |:---------------------------------|
+| Initialize SDK | InteractionCodeFlow |
+| Request initial step | InteractionCodeFlow |
+| Receive step | IdxResponse |
+| Check completion, cancel, or error | IdxResponse
IdxRemediation |
+| Gather user input | IdxRemediation
Capability |
+| Send input | InteractionCodeFlow |
+| Done | IdxResponse |
diff --git a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/processresponse.md b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/processresponse.md
index 614c0bbae89..7cd5b97e3a1 100644
--- a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/processresponse.md
+++ b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/processresponse.md
@@ -1,6 +1,9 @@
The following code shows these steps in order:
```kotlin
+import com.okta.authfoundation.client.OidcClientResult
+import com.okta.idx.kotlin.dto.IdxResponse
+
private suspend fun handleResponse(response: IdxResponse) {
// Check if the sign-in flow is successful.
if (response.isLoginSuccessful) {
@@ -36,11 +39,11 @@ private suspend fun handleResponse(response: IdxResponse) {
*/
private fun proceed(remediation: IdxRemediation) {
viewModelScope.launch {
- when (val resumeResult = client?.proceed(remediation)) {
- is IdxClientResult.Error -> {
+ when (val resumeResult = flow?.proceed(remediation)) {
+ is OidcClientResult.Error -> {
// Handle the error.
}
- is IdxClientResult.Success -> {
+ is OidcClientResult.Success -> {
handleResponse(resumeResult.result)
}
}
diff --git a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/signingout.md b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/signingout.md
index 693c93f686c..bf98466f48c 100644
--- a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/signingout.md
+++ b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/android/signingout.md
@@ -1,42 +1,24 @@
This code assumes storing the access token after a successful sign-in flow:
```kotlin
+import com.okta.authfoundation.client.OidcClientResult
+import com.okta.authfoundation.credential.RevokeTokenType
+import com.okta.authfoundationbootstrap.CredentialBootstrap
+
fun logout() {
- viewModelScope.launch(Dispatchers.IO) {
- try {
- // First load a refresh token if one exists.
- val refreshToken = Storage.tokens.refreshToken
- if (refreshToken != null) {
- // Revoking the refresh token also revokes the access token.
- revokeToken("refresh_token", refreshToken)
- } else {
- revokeToken("access_token", Storage.tokens.accessToken)
+ viewModelScope.launch {
+ // Revoking the refresh token also revokes the access token.
+ when (val revokeResult =
+ CredentialBootstrap.defaultCredential().revokeToken(RevokeTokenType.REFRESH_TOKEN)
+ )
+ {
+ is OidcClientResult.Error -> {
+ // Sign-out failed, handle the error.
+ }
+ is OidcClientResult.Success -> {
+ // Sign-out successful. Redirect to a sign-in view.
}
-
- // Sign-out successful. Redirect to a sign-in view.
- } catch (e: Exception) {
- // Sign-out failed, handle the error.
}
}
}
-
-
-private fun revokeToken(tokenType: String, token: String) {
- // Create an API request to revoke the token.
- val formBody = FormBody.Builder()
- .add("client_id", BuildConfig.CLIENT_ID)
- .add("token_type_hint", tokenType)
- .add("token", token)
- .build()
-
- val request = Request.Builder()
- .url("${BuildConfig.ISSUER}/v1/revoke")
- .post(formBody)
- .build()
-
- // Send the request to revoke the token.
- val response = OktaIdxClientConfigurationProvider.get().okHttpCallFactory.newCall(request).execute()
-
- println("Revoke Token Response: $response")
-}
```
diff --git a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/index.md b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/index.md
index 20d4acb750a..68c461bd974 100644
--- a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/index.md
+++ b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/index.md
@@ -2,7 +2,7 @@
title: Overview of the mobile Identity Engine SDK
---
-Design the implementation of the sign-in flow for your mobile app by understanding the representation of the flow and the associated objects.
+Design the implementation of sign-in for your mobile app by understanding the objects and messages that represent the sign-in flow.
@@ -17,9 +17,9 @@ This guide is an overview of building your own user interface using the embedded
## Sign-in flow
-Okta supports many ways of authenticating the identity of a user during the sign-in flow. An Okta org administrator creates _policies_, different mixes of *authenticators*, or ways of verifying the identity of a user, and assigns them to apps, people, groups, and more. Policies also configure whether an authenticator is required or optional, as well as the minimum number of authenticators required for a successful sign-on. Many flows require multiple *factors* (multifactor authentication), the category of an authenticator. Factors include biometrics, such as a fingerprint, knowledge, such as a password, and more. This results in a many of possible combinations of the different authenticators, the steps in the sign-in flow.
+Okta supports many ways of authenticating the identity of a user during the sign-in flow. An Okta org administrator creates _policies_, different mixes of *authenticators*, or ways of verifying the identity of a user, and assigns them to apps, people, groups, and more. Policies also configure whether an authenticator is required or optional and the minimum number required to sign in successfully. Responding to each authenticator is a step in the sign-in flow. Many flows require multiple *factors* (multifactor authentication), the category of an authenticator. Factor types include biometrics, such as a fingerprint, knowledge, such as a password, and more. This effectively results in an infinite number of combinations of authenticators and the order in which they're presented.
-The Android and iOS Identity Engine SDKs represent the sign-in flow as a state machine. You initialize the machine with the details of your Okta org app integration, request the initial step in the flow, and cycle through responding to steps until either the user signs in, cancels, or an error occurs.
+The Android and Swift Identity Engine SDKs represent the sign-in flow as a state machine. The Swift SDK is used for iOS. You initialize the machine with the details of your Okta org app integration, request the initial step in the flow, and cycle through responding to steps until either the user signs in, cancels, or an error occurs.
@@ -30,7 +30,7 @@ The Android and iOS Identity Engine SDKs represent the sign-in flow as a state m
Each sign-in step may include one or more possible user actions, such as:
- Choosing an authenticator, such as Okta Verify or security questions.
-- Entering an OTP.
+- Entering a one-time passcode (OTP).
- Cancelling the sign-in flow.
## Sign-in objects
@@ -44,55 +44,39 @@ The SDK represents the sign-in flow using a number of different objects:
- **Response:** The top-level object that represents a step and contains all the other objects. It includes a property that indicates a successful sign-in and functions for cancelling the sign-in flow, or retrieving the access token after the sign-in flow succeeds. A response may contain multiple authenticators and remediations.
-- **Remediation:** Represents the main user actions for a step, such as enrolling in an authenticator or entering an OTP. It includes a function for requesting the next step in the flow.
+- **Remediation:** Represents the main user actions for a step, such as enrolling in an authenticator or entering an OTP. In the Swift SDK for iOS, it also includes the function for requesting the next step in the flow.
- **Authenticator:** Represents an authenticator that's used to verify the identity of a user, such as Okta Verify.
-- **Method:** Represents a channel for an authenticator, such as using SMS or voice for an authenticator that uses a phone. An authenticator may have zero or more.
-- **Capability:** A user action associated with a remediation, authenticator, or method, such as requesting a new OTP or a password reset.
-- **Field:** Represents a UI element, either a static item, such as a label, or user input, such as a selection list. It includes properties for state information, such as whether the associated value is required. Properties also store the current value of user input field, such as the string for an OTP or the selected choice. Options, or lists of choices, are represented by a collection of fields. A field may contain a form that contains more fields.
+- **Method:** Represents a channel for an authenticator, such as using SMS or voice for an authenticator that uses a phone. An authenticator may have zero or more methods.
+- **Capability:** A user action or additional information that is associated with a remediation, authenticator, or method, such as requesting a new OTP or a redacted email.
+- **Field:** Represents a UI element, either a static item, such as a label, or user input, such as a selection list. It includes properties for state information, such as whether the associated value is required. Properties also store the current value of user input field, such as the string for an OTP or the selected choice. A lists of choices, or **Options**, are represented by a collection of fields. A field may contain a form that contains more fields.
- **Form:** Contains the fields that represent the user action for a remediation.
-- **Configuration:** Contains the settings used by the SDK to connect to your Okta org app integration.
-- **Client:** Represents the session during the sign-in flow.
+- **InteractionCodeFlow:** Represents the session during the sign-in flow. In the Android SDK, it includes the function for requesting the next step in the flow.
## Objects and the flow
-
-
-!["A diagram that shows the main objects associated with each step in the sign-in flow."](/img/mobile-sdk/mobile-idx-objects-and-flow.png)
-
-
-
-The main objects associated with each step in the flow are:
+
-| Sign-in step | Objects |
-| :--------------------------------- | :------------------------------ |
-| Initialize SDK | Configuration
Client |
-| Request initial step | Client |
-| Receive step | Response |
-| Check completion, cancel, or error | Response
Remediation |
-| Gather user input | Remediation
Authenticator |
-| Send input | Remediation |
-| Done | Response |
+## Manage the flows
+Add support for the sign-in and sign-out flows to your app:
-## Common parts of the flow
-
-Some parts of the sign-in flow are the same:
-
-- Add the SDK to your app.
-- Configure the SDK.
-- Initialize the client and start the flow.
-- Process the response.
-- Request a token.
+- Initialize the flow.
+- Start the flow.
+- Process responses until the sign-in flow succeeds, results in an error, or the user cancels the flow.
+- Request a token object for a successful sign-in flow. The object contains access, ID, and refresh tokens.
- Sign the user out.
+
### Add the SDK
+Before you add support you need to add the SDK to your project.
+
-### Create and manage configurations
+### Initialize the flow
-The values for a configuration object are:
+Configure the flow with the information it needs to communicate with your Okta org application integration:
| Value | Description |
| :------------ | :---------- |
@@ -103,11 +87,11 @@ The values for a configuration object are:
The configuration information in a shipping app is usually static. You can initialize the configuration values directly in the code or read them from a file. During development you may want to provide a way to edit configuration values.
-
+
-### Start sign-in
+### Start the sign-in flow
-Start the sign-in flow by creating an SDK client, and then requesting the first step.
+Start the sign-in flow after initializing an `InteractionCodeFlow` object.
@@ -115,13 +99,13 @@ Start the sign-in flow by creating an SDK client, and then requesting the first
The steps for processing a response are:
-1. Check for a successful sign-in flow.
+1. Check if the sign-in flow succeeded.
1. Check for messages, such as an invalid password.
1. Check for remediations.
1. Process the remediations.
1. Process the authenticators.
-After the user enters the required information, update the remediation and request the next step.
+After the user enters any required information, update the remediation and request the next step.
diff --git a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/adddependency.md b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/adddependency.md
index 42629a4d96e..9f123cc7535 100644
--- a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/adddependency.md
+++ b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/adddependency.md
@@ -4,8 +4,10 @@ The Okta Identity Engine SDK is available as a Swift package. Add it to your pro
1. Choose the approriate dependency (usually "Up to Next Major Version").
1. Click **Add Package**.
-Import the package into Swift files to access the SDK:
+The SDK includes a dependency on the Okta `AuthFoundation` library.
+Import the packages into Swift files to access the SDK:
```swift
import OktaIdx
+import AuthFoundation
```
diff --git a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/gettingatoken.md b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/gettingatoken.md
index cf58f321535..3bd74da77ed 100644
--- a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/gettingatoken.md
+++ b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/gettingatoken.md
@@ -1,32 +1,56 @@
-This example shows part of the implementation of the `IDXClientDelegate` protocol functions the SDK calls for each response and for receiving the access token.
+Getting the authorization token takes two steps.
-```swift
-
-import OktaIdx
-
-class SignInController {
- ...
+1. Request an access token after the sign-in flow is successful.
+1. Receive that token from the server.
- var currentResponse: Response? = nil
+The access token is represented by a `Token` object from the `AuthFoundation` library that is a dependency for the Swift IDX SDK. You can store the token securely in the keychain using `Credential`, another class from the `AuthFoundation` library.
- ...
+This example shows part of the implementation of the `InteractionCodeFlowDelegate` protocol functions that are called as part of getting the authorization token.
- // Delegate function called for each sign-in step.
- public func idx(client: IDXClient, didReceive response: Response) {
- currentResponse = response
- // If a response is successful, exchange the session token for an access token.
- guard !response.isLoginSuccessful else {
- response.exchangeCode()
- return
- }
+```swift
- ...
- }
+import OktaIdx
+import AuthFoundation
+
+class SignInController: InteractionCodeFlowDelegate, ObservableObject {
+
+// ...
+
+ // Set to true after the user has signed in successfully.
+ @MainActor @Published var successfulSignIn: Bool = false
+
+ // Delegate function called for each sign-in step.
+ func authentication(flow: Flow, received response: Response) where Flow : InteractionCodeFlow {
+ // If a sign-in is successful then request a token from the server.
+ if response.isLoginSuccessful {
+ Task {
+ do {
+ let _ = try await response.exchangeCode()
+ } catch {
+ DispatchQueue.main.async {
+ self.currentError = error
+ }
+ }
+ }
+ } else {
+// ...
+ }
+ }
+
+ // Delegate function called when a token is successfully exchanged.
+ func authentication(flow: Flow, received token: Token)
+ {
+ // Setting the default credential also stores the token
+ Credential.default = Credential(token: token)
+ //
+ DispatchQueue.main.async {
+ self.successfulSignIn = true
+ }
+ }
+
+// ...
+}
+```
- // Delegate function called when a token is successfully exchanged.
- public func idx(client: IDXClient, didReceive token: Token) {
- // Save the token securely and finish the sign-in flow.
- }
-```
diff --git a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/initializeflow.md b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/initializeflow.md
new file mode 100644
index 00000000000..2058511417f
--- /dev/null
+++ b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/initializeflow.md
@@ -0,0 +1,44 @@
+You can provide the configuration information in a property list file or in the initialization call.
+
+#### Add configuration with a property list
+
+The default `init()` function of `InteractionCodeFlow` looks for a property list called `Okta.plist`. You can specify a property list file by calling `init(plist:)`. Both of those options can result in an exception as they read from the file system. To specify the values in the call, use `init(
+ issuer:clientId:scopes:redirectUri:additionalParameters:)`.
+
+To use a property list first create a property list file, such as `Okta.plist`. Next, add key-value pairs with the configuration settings for your app integration. For example, in the following text version of a `plist`, substitute your issuer URL for `{yourIssuerUrl}`, the client ID of your app integration for `{yourClientId}`, and a URI that launches your app for `{com.your.app:callback-uri}`. Set the scopes based on the access required by your app.
+
+```xml
+
+
+
+
+ issuer
+ {yourIssuerUrl}
+ clientId
+ {yourClientId}
+ redirectUri
+ {com.your.app:/callback-uri}
+ scopes
+ openid email profile offline_access
+
+
+```
+
+Then, add code to create an `InteractionCodeFlow`, this example uses `Okta.plist`.
+
+```swift
+let flow = InteractionCodeFlow()
+```
+
+#### Add configuration in the code
+
+The example below adds the values in the initialization call.
+
+```swift
+let flow = InteractionCodeFlow(
+ issuer: "https://{yourOktaDomain}/oauth2/default",
+ clientId: "{yourClientId}",
+ clientSecret: nil,
+ scopes: ["openid", "email", "offline_access"],
+ redirectUri: "{com.your.app:/callback-uri}")
+```
diff --git a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/initializingsdksession.md b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/initializingsdksession.md
index 6f0089d3f6e..02e8aecf153 100644
--- a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/initializingsdksession.md
+++ b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/initializingsdksession.md
@@ -1,52 +1,52 @@
-This example shows parts of a singleton class for handling the sign-in flow. It initializes the client using the configuration example shown earlier.
+This example shows parts of a singleton class for managing the sign-in flow. It assumes that the configuration information is in a property list file called `Okta.plist`.
```swift
import OktaIdx
-
-struct OktaPlistContent: Codable {
-...
+import AuthFoundation
+
+class SignInController: InteractionCodeFlowDelegate, ObservableObject {
+ static let shared = SignInController()
+
+ // Published properties for the main state information of the flow
+ @MainActor @Published var currentResponse: Response? = nil
+ @MainActor @Published var currentRemediation: Remediation? = nil
+ @MainActor @Published var currentMessage: Response.Message? = nil
+ @MainActor @Published var currentError: Error? = nil
+
+ // Set to true after the user has signed in successfully.
+ @MainActor @Published var successfulSignIn: Bool = false
+
+ private var flow: InteractionCodeFlow?
+
+ private init() { }
+
+// ...
+
+ @MainActor
+ public func start() async throws {
+ do {
+ // Call the init method that loads the configuration information from Okta.plist.
+ try flow = InteractionCodeFlow()
+ } catch {
+ // An error occured inializating the SDK. Handle the error.
+ currentError = error
+ return
+ }
+
+ // Receive calls when responses or errors are returned.
+ flow!.add(delegate: self)
+
+ do {
+ // Request an initial response from the server.
+ // Responses call the appropriate InteractionCodeFlowDelegate function.
+ let response = try await flow!.start()
+ currentResponse = response
+ } catch {
+ currentError = error
+ }
+ }
+
+// ...
}
-
-class SignInController {
- // Return the singleton controller, creating the instance on the first call.
- static let shared: SignInController? = {
- let instance = SignInController(configuration: nil,
- client: nil)
-
- return instance
- }()
-
- var configuration: IDXClient.Configuration?
- var client: IDXClient?
-
- ...
-
-
- // Create a client and request the first response.
- func initializeSDK() {
- guard let configuration = loadConfiguration() else {
- // Could not create a configuration. Handle the error.
- return
- }
-
- self.configuration = configuration
-
- IDXClient.start(with: configuration) { (client, error) in
- guard let client = client else {
- // Handle the error.
- return
- }
-
- self.client = client
-
- // Request the first response.
- client.resume()
- }
- }
-
- func loadConfiguration() -> IDXClient.Configuration? {
- ...
- }
-
-
```
+
diff --git a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/loadingaconfiguration.md b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/loadingaconfiguration.md
deleted file mode 100644
index 29d5afe4bbb..00000000000
--- a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/loadingaconfiguration.md
+++ /dev/null
@@ -1,60 +0,0 @@
-Initialize a configuration by passing the appropriate values to `IDXClient.Configuration(issuer:clientId:clientSecret:scopes:redirectUri:)`. This example shows loading the values from a property file in your project.
-
-First, create a property list file, such as `Okta.plist`. Next, add key-value pairs with the configuration settings for your application integration. For example, in the following text version of a `plist`, substitute your issuer URL for `{yourIssuerUrl}`, the client ID of your application integration for `{yourClientId}`, and a URI that launches your app. Set the scopes based on the access required by your app.
-
-```xml
-
-
-
-
- issuer
- {yourIssuerUrl}
- clientId
- {yourClientId}
- redirectUri
- com.sample.:/callback
- scopes
- openid email profile offline_access
-
-
-```
-
-Next, add code to create an `IDXClient.Configuration` instance from the property list file. This example uses a decoder to read the values into an `OktaPlistContent` structure.
-
-```swift
-import OktaIdx
-
-...
-
-// A struct that represents the configuration in a plist.
-struct OktaPlistContent: Codable {
- var scopes: String
- var redirectUri: String
- var clientId: String
- var clientSecret: String
- var issuer: String
-
- var scopeArray: [String] {
- get {
- scopes.components(separatedBy: " ")
- }
- }
-}
-
-// Read the contents of the plist and return a configuration.
-func loadConfiguration() -> IDXClient.Configuration? {
- let decoder = PropertyListDecoder()
-
- guard let data = try? Data.init(contentsOf: plistURL),
- let configuration = try? decoder.decode(OktaPlistContent.self, from: data)
- else { return nil }
-
- // NOTE: The client secret isn't used on mobile.
- return IDXClient.Configuration(issuer: configuration.issuer,
- clientId: configuration.clientId,
- clientSecret: nil,
- scopes: configuration.scopeArray,
- redirectUri: configuration.redirectUri)
-}
-
-```
diff --git a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/objectsandflow.md b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/objectsandflow.md
new file mode 100644
index 00000000000..aefa8229526
--- /dev/null
+++ b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/objectsandflow.md
@@ -0,0 +1,17 @@
+
+
+!["A diagram that shows the main objects associated with each step in the sign-in flow."](/img/mobile-sdk/mobile-idx-objects-and-flow-swift.png)
+
+
+
+The main objects associated with each step in the flow are:
+
+| Sign-in step | Objects |
+| :--------------------------------- | :------------------------------ |
+| Initialize SDK | InteractionCodeFlow |
+| Request initial step | InteractionCodeFlow |
+| Receive step | Response |
+| Check completion, cancel, or error | Response
Remediation |
+| Gather user input | Remediation
Authenticator |
+| Send input | Remediation |
+| Done | Response |
diff --git a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/processresponse.md b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/processresponse.md
index 18f327a1220..e47a52db027 100644
--- a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/processresponse.md
+++ b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/processresponse.md
@@ -1,47 +1,90 @@
-This example shows part of the implementation of the `IDXClientDelegate` protocol functions called by the SDK for each response and for errors.
+This example shows part of the implementation of the `InteractionCodeFlowDelegate` protocol functions called by the SDK for different parts of the sign-in flow and for errors.
+
+The example publishes important state variables, such as the current response. A controller or SwiftUI view can subscribe to changes and update the UI. One advantage of this model is that you can reuse your sign-in controller in other apps.
```swift
import OktaIdx
+import AuthFoundation
+
+class SignInController: InteractionCodeFlowDelegate, ObservableObject {
+ static let shared = SignInController()
+
+ // Published properties for the main state information of the flow
+ @MainActor @Published var currentResponse: Response? = nil
+ @MainActor @Published var currentRemediation: Remediation? = nil
+ @MainActor @Published var currentMessage: Response.Message? = nil
+ @MainActor @Published var currentError: Error? = nil
+
+ // Set to true after the user has signed in successfully.
+ @MainActor @Published var successfulSignIn: Bool = false
+
+ private var flow: InteractionCodeFlow?
-class SignInController: IDXClientDelegate {
- ...
+ private init() { }
- var currentResponse: Response? = nil
+// ...
- ...
+ // Delegate function called for each sign-in step.
+ func authentication(flow: Flow, received response: Response)
+ where Flow : InteractionCodeFlow {
+ // Request a token from the server if the sign-in attempt is successful.
+ if response.isLoginSuccessful {
+ // Handle retrieving the access token.
+ } else {
+ DispatchQueue.main.async {
+ // Publish the new response for any listeners
+ self.currentResponse = response
- // Delegate function called for each sign-in step.
- public func idx(client: IDXClient, didReceive response: Response) {
- currentResponse = response
+ // Check for messages, such as entering an incorrect code.
+ if let message = response.messages.allMessages.first {
+ // Publish the message for listners to update state,
+ // such as showing a message in the UI.
+ self.currentMessage = message
+ return
+ }
- // If a response is successful, exchange it for a token.
- guard !response.isLoginSuccessful else {
- // Handle retrieving the access token.
- return
- }
+ // If no remediations are present, abort the login process.
+ guard let remediation = self.currentResponse?.remediations.first else {
+ return
+ }
+ // Publish the new remediation.
+ self.currentRemediation = remediation
+ }
+ }
+ }
- // If no remediations are present, abort the sign-in flow.
- guard let remediation = currentResponse?.remediations.first else {
- // Handle the error and finish the sign-in flow.
- return
- }
+ // Delegate function called when a token is successfully exchanged.
+ func authentication(flow: Flow, received token: Token) {
+ // Securely store the token for the user.
+ }
- // Check for messages, such as entering an incorrect code.
- if let message = response.messages.allMessages.first {
- // Handle the messages as appropriate.
- return
- }
+ // Delegate function called before the first sign-in step.
+ func authenticationStarted(flow: Flow) {
+ // Do any initialization required by your app.
+ }
- // Build the UI using the information in the remediations and authenticators.
+ // Delegate function called after the sign-in flow is complete.
+ func authenticationFinished(flow: Flow) {
+ // Do any cleanup required by your app and update the UI as appropriate.
+ }
- ...
- }
+ // Delegate functions called when errors occur
+ func authentication(flow: Flow, received error: InteractionCodeFlowError)
+ where Flow : InteractionCodeFlow {
+ // Publish the error from the main thread.
+ DispatchQueue.main.async {
+ self.currentError = error
+ }
+ }
- // Delegate function sent when an error occurs.
- public func idx(client: IDXClient, didReceive error: Error) {
- // Handle the error and finish the sign-in flow.
- }
+ func authentication(flow: Flow, received error: OAuth2Error) {
+ // Publish the error from the main thread.
+ DispatchQueue.main.async {
+ self.currentError = error
+ }
+ }
+}
```
diff --git a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/signingout.md b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/signingout.md
index 19532b2a883..d30f5707972 100644
--- a/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/signingout.md
+++ b/packages/@okta/vuepress-site/docs/guides/mobile-idx-sdk-overview/main/ios/signingout.md
@@ -1,94 +1,18 @@
-This singleton stores the token in user defaults. For more security, store the token in the Keychain.
+The code snippet below uses the `Credential` object of the `AuthFoundation` library to revoke the tokens for the current user. You can use other features of `Credential` to revoke the tokens of a specific user.
```swift
-import Foundation
import OktaIdx
+import AuthFoundation
-enum TokenManagerError: Error {
- case unableToReadToken(String)
-}
-
-class TokenManager {
- static let shared = TokenManager()
-
- // Change com.example.okta-samplecode.Okta-Login to your bundle identifier.
- private struct UserDefaultsKeys {
- static let storedTokenKey = "com.example.okta-samplecode.Okta-Login.storedToken"
- }
-
- // Save the token to user defaults.
- func saveToken(_ token: Token) {
- let defaults = UserDefaults.standard
-
- // Convert the token to a format that you can save in user defaults.
- guard let tokenData = try? JSONEncoder().encode(token) else {
- // Handle the error.
- return
- }
-
- defaults.set(tokenData, forKey: UserDefaultsKeys.storedTokenKey)
- defaults.synchronize()
- }
-
- // Read the token from user defaults.
- func readToken() -> Token? {
- // Check for an existing token and convert from JSON to an SDK Token object.
- guard let tokenData = UserDefaults.standard.object(forKey: UserDefaultsKeys.storedTokenKey) as? Data,
- let token = try? JSONDecoder().decode(Token.self, from: tokenData) else {
- // Handle the error.
- return nil
- }
-
- return token
- }
-
- func revokeToken(completion: @escaping(_ successful: Bool, _ error: Error?) -> Void) {
- if let token = readToken() {
- token.revoke() { (success, error) in
- let defaults = UserDefaults.standard
- if success {
- // Delete the token from user defaults.
- defaults.removeObject(forKey: UserDefaultsKeys.storedTokenKey)
- defaults.synchronize()
-
- completion(true, nil)
- } else {
- completion(false, error)
- }
- }
- } else {
- completion(false, TokenManagerError.unableToReadToken("Unable to read the Token."))
- return
- }
- }
-}
-```
-
-This code shows the delegate function that handles receiving the access token:
+class SignInController: InteractionCodeFlowDelegate, ObservableObject {
+// ...
-
-```swift
-public func idx(client: IDXClient, didReceive token: Token) {
- TokenManager.shared.save(token)
+ // Sign out the current user.
+ public func signOut() throws {
+ try await Credential.default?.revoke()
+ }
}
```
-Revoke a token by calling `Token.revoke(type:completion:)` (`type` is optional):
-
-```swift
-if let token = TokenManager.shared.readToken() {
- token.revoke() { (success, error) in
- guard success else {
- // Handle the error.
- return
- }
- // The token is revoked.
- // In SwiftUI, update variables for presenting UI.
- // For ViewControllers perform the call on the main thread using `DispatchQueue.main.async`.
- return
- }
-}
-```
-