Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mds/okta 524282/okta 528021 update mobile sdk overview #4332

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified ...okta/vuepress-site/.vuepress/public/img/mobile-sdk/mobile-idx-basic-objects.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
Original file line number Diff line number Diff line change
@@ -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))
}
```
Original file line number Diff line number Diff line change
@@ -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)
}
}
}
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<div class="full">

!["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)

</div>

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 <br/> IdxRemediation |
| Gather user input | IdxRemediation <br/> Capability |
| Send input | InteractionCodeFlow |
| Done | IdxResponse |
mauricesharp-okta marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -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) {
Expand Down Expand Up @@ -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)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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")
}
```
Loading