{"id":22808949,"url":"https://github.com/okta/okta-mobile-kotlin","last_synced_at":"2025-09-09T19:26:52.013Z","repository":{"id":37855420,"uuid":"445628677","full_name":"okta/okta-mobile-kotlin","owner":"okta","description":"Okta's Android Authentication SDK","archived":false,"fork":false,"pushed_at":"2025-08-20T17:00:26.000Z","size":3765,"stargazers_count":41,"open_issues_count":29,"forks_count":15,"subscribers_count":77,"default_branch":"master","last_synced_at":"2025-08-20T19:25:05.696Z","etag":null,"topics":["android","authentication","jwt","kotlin","oauth","oidc","okta","openid-connect"],"latest_commit_sha":null,"homepage":"https://okta.github.io/okta-mobile-kotlin/","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/okta.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-01-07T19:18:31.000Z","updated_at":"2025-08-20T17:00:27.000Z","dependencies_parsed_at":"2023-09-22T05:24:48.938Z","dependency_job_id":"90ecbb88-177c-45b1-a9b5-bcb905fcc3da","html_url":"https://github.com/okta/okta-mobile-kotlin","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/okta/okta-mobile-kotlin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/okta%2Fokta-mobile-kotlin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/okta%2Fokta-mobile-kotlin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/okta%2Fokta-mobile-kotlin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/okta%2Fokta-mobile-kotlin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/okta","download_url":"https://codeload.github.com/okta/okta-mobile-kotlin/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/okta%2Fokta-mobile-kotlin/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274348781,"owners_count":25268972,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-09T02:00:10.223Z","response_time":80,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","authentication","jwt","kotlin","oauth","oidc","okta","openid-connect"],"created_at":"2024-12-12T11:12:58.531Z","updated_at":"2025-09-09T19:26:52.001Z","avatar_url":"https://github.com/okta.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Support](https://img.shields.io/badge/support-Developer%20Forum-blue.svg)][devforum]\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n\n# Okta Mobile Kotlin\n\u003e _”Make the easy things simple and make the hard things possible.”_\n\nThe Okta Mobile SDKs are a suite of libraries that intends to replace our legacy mobile SDKs, with the aim to streamline development, ease maintenance and feature development, and enable new use cases that were previously difficult or impractical to implement. We are building a platform to support the development of many SDKs, allowing application developers to choose which SDKs they need.\n\nThe Okta Mobile Kotlin SDK is intended to be used on the Android platform.\n\n## SDK Overview\n\nThis SDK consists of several different libraries, each with detailed documentation.\n\n- [AuthFoundation](auth-foundation) -- Common classes for managing credentials and used as a foundation for other libraries.\n- [OktaOAuth2](oauth2) -- OAuth2 authentication capabilities for authenticating users.\n- [WebAuthenticationUI](web-authentication-ui) -- Authenticate users using web-based OIDC flows.\n- [OktaIdx](okta-idx-kotlin/README.md) -- Okta's Identity Engine support using Okta's IDX API for native browserless authentication.\n\n## Support Policy\n\n### Legacy okta-oidc-android support\n\nWe intend to support okta-oidc-android with critical bug and security fixes for the foreseeable future. Once the Kotlin Mobile SDK is generally available, all new features will be built on top of okta-mobile-kotlin and will replace okta-oidc-android.\n\n## Unlocking use cases\nOkta is busy adding new functionality to its identity platform. We're excited to unlock these new capabilities for Android. These SDKs are built on top of [Kotlin](https://kotlinlang.org/), [Kotlin Coroutines](https://kotlinlang.org/docs/coroutines-overview.html), and [OkHttp](https://github.com/square/okhttp). We are doubling down on our developer experience, providing seamless ways to log in, store, and access OAuth tokens. We are building an initial set of functionality unlocking new OAuth flows that were not possible before, including:\n* [Token Exchange](https://datatracker.ietf.org/doc/html/rfc8693)\n* [Device Authorization Grant](https://datatracker.ietf.org/doc/html/rfc8628)\n* [Okta Identity Engine](https://github.com/okta/okta-idx-android)\n\n# Installation\n\nAdd the `Okta Mobile Kotlin` dependencies to your `build.gradle` file:\n\n```gradle\n// Ensure all dependencies are compatible using the Bill of Materials (BOM).\nimplementation(platform('com.okta.kotlin:bom:2.0.3'))\n\n// Add the dependencies to your project.\nimplementation('com.okta.kotlin:auth-foundation')\nimplementation('com.okta.kotlin:oauth2')\nimplementation('com.okta.kotlin:web-authentication-ui')\n```\n\nSee the [CHANGELOG](CHANGELOG.md) for the most recent changes.\n\nIf you're migrating from [okta-oidc-android](https://github.com/okta/okta-oidc-android) see [migrate.md](migrate.md) for more information.\n\n# Okta Mobile SDK for Kotlin\n\n## Release status\n\nThis library uses semantic versioning and follows Okta's [Library Version Policy][okta-library-versioning].\n\nThe latest release can always be found on the [releases page][github-releases].\n\n## Need help?\n\nIf you run into problems using the SDK, you can:\n\n* Ask questions on the [Okta Developer Forums][devforum]\n* Post [issues][github-issues] here on GitHub (for code errors)\n\n## Getting Started\n\nTo get started, you will need:\n\n* An Okta account, called an _organization_ (sign up for a free [developer organization](https://developer.okta.com/signup) if you need one).\n* An Okta Application, configured as a Native App. This is done from the Okta Developer Console. When following the wizard, use the default properties. They are designed to work with our sample applications.\n* Android Studio\n\n## Usage Guide\n\nThis SDK consists of several different libraries, each with their own detailed documentation.\n\nSDKs are split between two primary use cases:\n- Minting tokens (authentication)\n  - Okta supports many OAuth flows, our Android SDKs support the following: Authorization Code, Interaction Code, Refresh Token, Resource Owner Password, Device Authorization, and Token Exchange.\n- Managing the token lifecycle (refresh, storage, validation, etc)\n\n### Auto backup rules\n\nThis SDK uses on-device encryption keys to store data. Because of this, the SDK files should not be backed up. This SDK provides backup rules to exclude files automatically.\nBut, if your application provides its own backup rules by specifying `android:dataExtractionRules` or `android:fullBackupContent`, please include SDK backup rules as specified in [data_extraction_rules](auth-foundation/src/main/res/xml/data_extraction_rules.xml) and [full_backup_content](auth-foundation/src/main/res/xml/full_backup_content.xml).\n\n### Kotlin Coroutines\n[Kotlin Coroutines](https://kotlinlang.org/docs/coroutines-overview.html) are used extensively throughout the SDKs. All methods can be used via any thread (including the main thread), and will switch to a background thread internally when performing network IO or expensive computation.\n\n### Web Authentication using OIDC redirect\n\nThe simplest way to integrate authentication in your app is with OIDC through a web browser, using the Authorization Code Flow grant.\n\n#### Configure your OAuth Settings\n\nBefore authenticating your user, you need to set your default `OidcConfiguration` using the settings defined in your application in the Okta Developer Console.\n\n```kotlin\nimport android.content.Context\nimport com.okta.authfoundation.AuthFoundation\nimport com.okta.authfoundation.client.OidcConfiguration\n\nval context: Context = TODO(\"Supplied by the developer.\")\nAuthFoundation.initializeAndroidContext(context)\nOidcConfiguration.default = OidcConfiguration(\n  clientId = \"{clientId}\",\n  defaultScope = \"openid email profile offline_access\",\n  issuer = \"https://{yourOktaOrg}.okta.com/oauth2/default\"\n)\n```\n\n#### Create a Web Authentication Client\n\nWe will create a `WebAuthentication` and use it to perform authentication.\n\nThis launches a [Chrome Custom Tab](https://developer.chrome.com/docs/android/custom-tabs/) to display the login form, and once complete, redirects back to the application.\n\n```kotlin\nimport android.content.Context\nimport com.okta.authfoundation.credential.Credential\nimport com.okta.oauth2.AuthorizationCodeFlow\nimport com.okta.webauthenticationui.WebAuthentication\n\nval context: Context = TODO(\"Supplied by the developer.\")\nval credential: Credential\nval redirectUrl: String = TODO(\"signInRedirectUri supplied by the developer.\")\nval auth = WebAuthentication()\nwhen (val result = auth.login(context, redirectUrl)) {\n    is OAuth2ClientResult.Error -\u003e {\n        // Timber.e(result.exception, \"Failed to login.\")\n        // TODO: Display an error to the user.\n    }\n    is OAuth2ClientResult.Success -\u003e {\n      credential = Credential.store(token = result.result)\n      Credential.setDefaultCredential(credential)\n      // The credential instance is now initialized! You can use the `Credential` to make calls to OAuth endpoints, or to sign requests!\n    }\n}\n```\n\nNext we need to be sure our application handles the redirect. Add the following snippet to your `build.gradle`:\n\nNote: you will need to replace the `{redirectUriScheme}` with your applications redirect scheme. For example, a `signInRedirectUri` of `com.okta.sample.android:/login` would mean replacing `{redirectUriScheme}` with `com.okta.sample.android`.\n\n```groovy\nandroid {\n  defaultConfig {\n    manifestPlaceholders = [\n      \"webAuthenticationRedirectScheme\": \"{redirectUriScheme}\"\n    ]\n  }\n}\n```\n\n### Device Authorization Flow\n\n[DeviceAuthorizationFlow](oauth2/src/main/java/com/okta/oauth2/DeviceAuthorizationFlow.kt) can be used to perform [OAuth 2.0 Device Authorization Grant](https://datatracker.ietf.org/doc/html/rfc8628).\n\nThe Device Authorization Flow is designed for Internet connected devices that either lack a browser to perform a user-agent based authorization or are input constrained to the extent that requiring the user to input text in order to authenticate during the authorization flow is impractical.\n\n```kotlin\nimport com.okta.authfoundation.credential.Credential\nimport com.okta.oauth2.DeviceAuthorizationFlow\n\nval credential: Credential\nval deviceAuthorizationFlow = DeviceAuthorizationFlow()\n\nwhen (val result = deviceAuthorizationFlow.start()) {\n  is OAuth2ClientResult.Error -\u003e {\n    // Timber.e(result.exception, \"Failed to login.\")\n    // TODO: Display an error to the user.\n  }\n  is OAuth2ClientResult.Success -\u003e {\n    val flowContext: DeviceAuthorizationFlow.Context = result.result\n    // TODO: Show the user the code and uri to complete the login via `flowContext.userCode` and `flowContext.verificationUri`.\n\n    // Poll the Authorization Server. When the user completes their login, this will complete.\n    when (val resumeResult = deviceAuthorizationFlow.resume(flowContext)) {\n      is OAuth2ClientResult.Error -\u003e {\n        // Timber.e(resumeResult.exception, \"Failed to login.\")\n        // TODO: Display an error to the user.\n      }\n      is OAuth2ClientResult.Success -\u003e {\n        credential = Credential.store(token = result.result)\n        Credential.setDefaultCredential(credential)\n        // The credential instance is now initialized! You can use the `Credential` to make calls to OAuth endpoints, or to sign requests!\n      }\n    }\n  }\n}\n```\n\n### Token Exchange Flow\n\n[TokenExchangeFlow](oauth2/src/main/java/com/okta/oauth2/TokenExchangeFlow.kt) can be used to perform [OIDC Native SSO](https://openid.net/specs/openid-connect-native-sso-1_0.html).\n\nThe Token Exchange Flow exchanges an ID Token and a Device Secret for a new set of tokens.\n\n```kotlin\nimport com.okta.authfoundation.client.OAuth2Client\nimport com.okta.authfoundation.credential.Credential\nimport com.okta.oauth2.TokenExchangeFlow\n\nval tokenExchangeFlow = TokenExchangeFlow()\nwhen (val result = tokenExchangeFlow.start(idToken, deviceSecret)) {\n  is OAuth2ClientResult.Error -\u003e {\n      // Timber.e(result.exception, \"Failed to login.\")\n      // TODO: Display an error to the user.\n  }\n  is OAuth2ClientResult.Success -\u003e {\n    val tokenExchangeCredential = Credential.store(result.result)\n    // The credential instance is now initialized! You can use the `Credential` to make calls to OAuth endpoints, or to sign requests!\n  }\n}\n```\n\n\u003e Note: You'll want to ensure you have 2 *DIFFERENT* `Credential`s. The first needs to have the `idToken`, and `deviceSecret` minted via a `WebAuthenticationClient`. The second will be used in the `TokenExchangeFlow`.\n\n### Logout\n\nThere are multiple terms that might be confused when logging a user out.\n\n- `Credential.delete` - Clears the in memory reference to the `Token` and removes the information from `TokenStorage`, the `Credential` can no longer be used.\n- `Credential.revokeAllTokens` - Revokes all available tokens from the Authorization Server.\n- `Credential.revokeToken`/`OAuth2Client.revokeToken` - Revokes the specified `RevokeTokenType` from the Authorization Server.\n- `WebAuthenticationClient.logoutOfBrowser` - Removes the Okta session if the user was logged in via the OIDC Browser redirect flow. Also revokes the associated `Token`(s) minted via this flow.\n\n\u003e Notes:\n\u003e - `Credential.delete` does not revoke a token\n\u003e - `Credential.revokeToken`/`Credential.revokeAllTokens`/`OAuth2Client.revokeToken` does not remove the `Token` from memory, or `TokenStorage`. It also does not invalidate the browser session if the `Token` was minted via the OIDC Browser redirect flow.\n\u003e - `WebAuthenticationClient.logoutOfBrowser` revokes the `Token`, but does not remove it from memory or `TokenStorage`\n\u003e - Revoking a `RevokeTokenType.ACCESS_TOKEN` does not revoke the associated `Token.refreshToken` or `Token.deviceSecret`\n\u003e - Revoking a `RevokeTokenType.DEVICE_SECRET` does not revoke the associated `Token.accessToken` or `Token.refreshToken`\n\u003e - Revoking a `RevokeTokenType.REFRESH_TOKEN` *DOES* revoke the associated `Token.accessToken` AND `Token.refreshToken`\n\n### Using a Credential to determine user authentication status\nThere are a few options to determine the status of a user authentication. Each option has unique pros and cons and should be chosen based on the needs of your use case.\n\n- Non null default credential: `Credential.default != null`\n- Non empty credential allIds: `Credential.allIds.isNotEmpty()`\n- getValidAccessToken: `Credential.default?.getValidAccessToken() != null`\n- Custom implementation: `Credential.default?.token`, `Credential.default?.refresh()`, and `Credential.default?.getAccessTokenIfValid()`\n\nDetails on each approach are below.\n\n#### Determine authentication status via non null Credential\n`Credential`s require a `Token`. If there are no `Credential`s present, then no `Token` has been stored. Note that `Credential.default` can throw a `BiometricInvocationException` if the `Credential` was stored using `Credential.Security.Biometric\u003cStrong/StrongOrDeviceCredential\u003e`.\n\n#### Determine authentication by checking if any Credentials exist\n`Credential.allIds` lists list of all ids of stored `Credential`s. If it returns an empty list, there are no stored `Credential`s.\n\n#### Determine authentication status via getValidAccessToken\n`Credential` has a method called `getValidAccessToken` which checks to see if the credential has a token, and has a valid access token. If the access token is expired, and a refresh token exists, a `refresh` is implicitly called on the `Credential`. If the implicit `refresh` is successful, `getValidAccessToken` returns the new access token. There are two main down sides to this approach. First, it's a `suspend fun` and could make network calls. Second, the failure is not returned, an error could occur due to a network error, a missing token, a missing refresh token, or a configuration error.\n\n#### Determine authentication status via custom implementation\nIf your use case requires insight into errors and the current state of the `Credential`, you can use implement it to your needs with the primitives `Credential` provides. See the documentation for the associated properties and methods: `Credential.token`, `Credential.refresh()`, `Credential.getAccessTokenIfValid()`.\n\n### Biometric Credentials\nThe SDK has built-in support for handling Biometric encryption. To set the default token encryption as Biometric, `Credential.Security.standard` can be set to `Credential.Security.BiometricStrong` or `Credential.Security.BiometricStrongOrDeviceCredential`. Biometric encryption also requires setting `Credential.Security.promptInfo`.\n\n\u003e Notes:\n\u003e - The SDK does not check which biometrics are enrolled on the user's device. Please check this using https://developer.android.com/reference/android/hardware/biometrics/BiometricManager#canAuthenticate(int) before setting the appropriate security level\n\u003e - The SDK automatically deletes Token entries stored using invalidated biometric keys.\n\u003e - Biometric Credentials should only be fetched using async APIs in `Credential` class, otherwise `BiometricInvocationException` will be thrown.\n\n#### Setting Biometric security for new Credentials globally\n\n```kotlin\nCredential.Security.standard = Credential.Security.BiometricStrong()\nCredential.Security.promptInfo = BiometricPrompt.PromptInfo.Builder()\n  .setTitle(\"Title\")\n  .setNegativeButtonText(\"Cancel Button\")\n  .setAllowedAuthenticators(BiometricManager.Authenticators.BIOMETRIC_STRONG) // Verify the authenticator is supported by device using BiometricManager.canAuthenticate\n  .build()\n```\n\n#### Setting Biometric security for a single Credential\n\n```kotlin\nval token = TODO(\"Supplied by user\")\nval credential = Credential.store(token, security = Credential.Security.BiometricStrong())\n```\n\n#### Auth-per-use Biometric keys\nThe SDK uses Biometric keys with a timeout of 5 seconds by default. This allows apps to invoke Biometrics once, and perform operations on multiple Biometric `Credential`s. Auth-per-use Biometric `Credential`s are also supported using the following:\n\n```kotlin\n// Globally\nCredential.Security.standard = Credential.Security.BiometricStrong(userAuthenticationTimeout = 0)\n// or per-Credential\nval token = TODO(\"Supplied by user\")\nval credential = Credential.store(token, security = Credential.Security.BiometricStrong(userAuthenticationTimeout = 0))\n```\n\n#### Biometric exceptions\nAndroid `BiometricPrompt` can fail due to `AuthenticationCallback.onAuthenticationFailed` and `AuthenticationCallback.onAuthenticationError`. See this relevant Android developer doc: [BiometricPrompt.AuthenticationCallback](https://developer.android.com/reference/kotlin/androidx/biometric/BiometricPrompt.AuthenticationCallback)\n\n`AuthenticationCallback.onAuthenticationError` can return error codes to recover from different Biometric situations, as listed here: https://developer.android.com/reference/kotlin/androidx/biometric/BiometricPrompt#ERROR_CANCELED()\n\nWhen using Biometric security, `Credential` fetching functions can throw `BiometricAuthenticationException`, and the relevant errors can be queried as follows:\n\n```kotlin\nval credential = try {\n    Credential.getDefaultAsync()\n} catch (ex: BiometricAuthenticationException) {\n    when (val details = ex.biometricExceptionDetails) {\n      is BiometricExceptionDetails.OnAuthenticationFailed -\u003e {\n        TODO(\"onAuthenticationFailed has no error codes or messages\")\n      }\n      is BiometricExceptionDetails.OnAuthenticationError -\u003e {\n        val errorMessage = details.errString\n        // Error code from https://developer.android.com/reference/kotlin/androidx/biometric/BiometricPrompt#constants_1\n        val errorCode = details.errorCode\n      }\n    }\n}\n```\n\n### Networking customization\n\nThe Okta Mobile Kotlin SDKs should provide all the required networking by default, however, if you would like to customize networking\nbehavior, that is also possible.\n\nThe SDK uses [OkHttp](https://github.com/square/okhttp) as the API for performing network requests.\nThe SDK also uses OkHttp as the default implementation for performing network requests.\nIf you intent to customize networking behavior, there are a few options:\n- Add an [Interceptor](https://square.github.io/okhttp/4.x/okhttp/okhttp3/-interceptor/) to the `OkHttpClient` you provide to\n`AuthFoundationDefaults.okHttpClientFactory`\n- Return a custom implementation of `Call.Factory` when initializing the SDK in `AuthFoundationDefaults.okHttpClientFactory`\n\n#### OkHttp Interceptor\n\nConfiguring the `OkHttpClient` with an `Interceptor` is the recommend approach to customizing the networking behavior.\nAdding an interceptor allows you to listen for requests and responses, customize requests before they are sent, and customize responses\nbefore they are processed by the SDK.\n\n#### Custom Call Factory\n\nProviding a custom call factory is an advanced use case, and is not recommended. The possibilities are endless, including the ability to\nreplace the engine that executes the HTTP requests.\n\n### Rate Limit Handling\n\nThe Okta API will return 429 responses if too many requests are made within a given time. Please see [Rate Limiting at Okta] for a complete\nlist of which endpoints are rate limited. This SDK automatically retries requests on 429 errors. The default configuration is as follows:\n\n| Configuration Option | Description |\n| ---------------------- | -------------- |\n| maxRetries         | The number of times to retry. The default value is `3`. |\n| minDelaySeconds    | The minimum amount of time to wait between each retry. The default value is `1` second. |\n\n#### Configuring retry parameters\n\nTo configure retry parameters, an `EventHandler` must be registered before creating an `OidcConfiguration`. In the `EventHandler`,\n`RateLimitExceededEvent` events will be emitted any time a request receives a response with 429 status code. `minDelaySeconds` and\n`maxRetries` can be adjusted based on details provided by the event.\n\n```kotlin\nimport com.okta.authfoundation.AuthFoundationDefaults\nimport com.okta.authfoundation.client.OidcConfiguration\nimport com.okta.authfoundation.client.events.RateLimitExceededEvent\nimport com.okta.authfoundation.events.EventCoordinator\nimport com.okta.authfoundation.events.EventHandler\n\nAuthFoundationDefaults.eventCoordinator = EventCoordinator(\n  object : EventHandler {\n    override fun onEvent(event: Any) {\n      when (event) {\n        is RateLimitExceededEvent -\u003e {\n          // Event info\n          val retriedRequest = event.request // Request that triggered the event\n          val responseWith429Code = event.response// 429 response to the request. Note: Only access the response body using response.peekBody\n          val retryCount = event.retryCount // Number of retries for this request so far\n\n          // User configurable flags\n          event.minDelaySeconds = 1L // User configurable delay, in seconds, for retrying the request again\n          event.maxRetries = 3 // User configurable max retries for this request\n        }\n      }\n    }\n  }\n)\n\nval oidcConfiguration = OidcConfiguration(\n  clientId = \"{clientId}\",\n  defaultScope = \"openid email profile offline_access\",\n)\n```\n\n## Migrating from okta-mobile-kotlin 1.x to 2.x\n\n### Token migration\n\nThe process for Token migration varies based on use of custom `TokenStorage` or encryption spec when creating `CredentialDataSource` in 1.x. Token migration is handled automatically in the simplest case without user intervention:\n\n```kotlin\nclient.createCredentialDataSource(context)\n```\n\n#### Migration with custom KeyGenParameterSpec\n\n1.x:\n```kotlin\nval keyGenParameterSpec: KeyGenParameterSpec = TODO(\"Supplied by user\")\nclient.createCredentialDataSource(context, keyGenParameterSpec)\n```\n2.x:\n```kotlin\nval keyGenParameterSpec: KeyGenParameterSpec = TODO(\"Supplied by user\")\nV1ToV2StorageMigrator.legacyKeyGenParameterSpec = keyGenParameterSpec\n```\n\n#### Migration with custom TokenStorage\n\n1.x:\n```kotlin\nval customTokenStorage: TokenStorage = TODO(\"Supplied by user\")\nclient.createCredentialDataSource(customTokenStorage)\n```\n\n2.x:\n```kotlin\n// Convert custom TokenStorage implementation to LegacyTokenStorage\nval legacyTokenStorage: LegacyTokenStorage = TODO(\"Supplied by user\")\nV1ToV2StorageMigrator.legacyStorage = legacyTokenStorage\n```\n\n### API migration\n\n#### Credential changes\n\n`CredentialBootstrap`, `CredentialDataSource`, and `Credential` contain several changes over 1.x. `Credential`s can no longer contain a null `Token`. Because of this change from 1.x, the flow for creating `Credential` without `Token`, followed by calling `Credential.storeToken` can no longer be used.\nWhen creating a new `Credential` with `Credential.store`, a `Token` must be provided.\n\n1.x would create a new `Credential` with null `Token` if no default `Credential` existed when calling `CredentialBootstrap.defaultCredential()`. In 2.x, default `Credential` can be fetched using `Credential.default` or `Credential.getDefaultAsync()`. Both of those have a type of `Credential?` instead of `Credential`, and return `null` if no default `Credential` exists.\n\n1.x contained `Credential` handling APIs in `CredentialBootstrap` and `CredentialDataSource`. All `Credential` management calls have been moved to `Credential` in 2.x. `CredentialBootstrap` has been deleted, and `CredentialDataSource` is private in 2.x.\n\n1.x provided `suspend` functions for handling creation and management of any `Credential`s. 2.x provides synchronous `Credential` management functions in addition to `suspend` functions.\n\n#### Initialization changes\n\nThe SDK initialization calls in 1.x were as follows:\n\n```kotlin\nval context: Context = TODO(\"Supplied by the developer.\")\nval oidcConfiguration = OidcConfiguration(\n    clientId = \"{clientId}\",\n    defaultScope = \"openid email profile offline_access\",\n)\nval client = OidcClient.createFromDiscoveryUrl(\n    oidcConfiguration,\n    \"https://{yourOktaOrg}.okta.com/oauth2/default/.well-known/openid-configuration\".toHttpUrl(),\n)\nCredentialBootstrap.initialize(client.createCredentialDataSource(context))\n```\n\nIn 2.x, this is changed to:\n```kotlin\nval context: Context = TODO(\"Supplied by the developer.\")\nAuthFoundation.initializeAndroidContext(context)\nOidcConfiguration.default = OidcConfiguration(\n  clientId = \"{clientId}\",\n  defaultScope = \"openid email profile offline_access\",\n  issuer = \"https://{yourOktaOrg}.okta.com/oauth2/default\" // Note that 1.x required .well-known/openid-configuration link. 2.x automatically handles this\n)\n```\n\n#### OAuth flows\n\nIn 1.x, OAuth flows were created as follows:\n\n```kotlin\nval oauthFlow = CredentialBootstrap.oidcClient.createWebAuthenticationClient() // or createTokenExchangeFlow, createDeviceAuthorizationFlow etc\n```\n\nIn 2.x, this has been changed to:\n\n```kotlin\nval oauthFlow = WebAuthentication() // or TokenExchangeFlow, SessionTokenFlow, DeviceAuthorizationFlow, or AuthorizationCodeFlow\n```\n\nBy default, all OAuth flows use `OAuth2Client` associated with `OidcConfiguration.default`. Custom `OAuth2Client` or `OidcConfiguration` can be passed into OAuth flows as follows:\n\n```kotlin\n// Custom OidcConfiguration\nval oidcConfiguration: OidcConfiguration = TODO(\"Supplied by user\")\nval oauthFlow = WebAuthentication(oidcConfiguration)\n\n// Custom OAuth2Client\nval client: OAuth2Client = TODO(\"Supplied by user\")\nval oauthFlow = WebAuthentication(client)\n```\n\n#### WebAuthenticationUi\n\n`WebAuthenticationClient` has been renamed to `WebAuthentication`.\n\n## Troubleshooting\n\n- java.lang.NoClassDefFoundError: Failed resolution of: Ljava/time/Instant;\n  - Fix: configure [Core Library Desugaring](https://developer.android.com/studio/write/java8-support#library-desugaring)\n\n### FlowCancelledException\n\nFlowCancelledException is supposed to be thrown in cases where the user has decided to cancel the login flow, usually by quitting the browser login window. It can sometimes be incorrectly thrown in the following cases:\n- Using the Android system webview while logging out. The webview doesn't store the session after a successful login, so logging out never redirects, and the user is forced to cancel logout process\n- Deleting the browser cache after logging in, then attempting to log out. Similar to the above, it is important for browser to store the login state to logout successfully, otherwise the browser can not provide the logout redirect.\n- Browser providing empty redirect results, followed by well-defined results. This has been observed in some older devices and browsers. This problem can be worked around by setting AuthFoundationDefaults.loginCancellationDebounceTime\n\n## Running the sample\n\nThe sample is designed to show what is possible when using the SDK.\n\n### Configuring the sample\n\nUpdate the `okta.properties` file in the root directory of the project with the contents created from the Okta admin dashboard:\n```\nissuer=https://YOUR_ORG.okta.com/oauth2/default\nclientId=test-client-id\nsignInRedirectUri=com.okta.sample.android:/login\nsignOutRedirectUri=com.okta.sample.android:/logout\nlegacySignInRedirectUri=com.okta.sample.android.legacy:/login\nlegacySignOutRedirectUri=com.okta.sample.android.legacy:/logout\n```\n\n\u003e Notes:\n\u003e - issuer - is your authorization server, usually https://your_okta_domain.okta.com/oauth2/default, but custom authorization servers are supported. See https://your_okta_domain.okta.com/admin/oauth2/as for available authorization servers.\n\u003e - clientId - is your applications client id, created in your Okta admin dashboard\n\u003e - signInRedirectUri - is used for browser redirect, and should follow the format of reverse domain name notation + /login, ie: com.okta.sample.android:/login\n\u003e - signOutRedirectUri - is used for browser redirect, and should follow the format of reverse domain name notation + /logout, ie: com.okta.sample.android:/logout\n\n### Launching the sample\n\nYou can open this sample in Android Studio or build it using Gradle.\n\n```\n./gradlew :app:assembleDebug\n```\n\n## Contributing\n\nWe are happy to accept contributions and PRs! Please see the [contribution guide](CONTRIBUTING.md) to understand how to structure a contribution.\n\n[devforum]: https://devforum.okta.com/\n[github-issues]: https://github.com/okta/okta-mobile-kotlin/issues\n[github-releases]: https://github.com/okta/okta-mobile-kotlin/releases\n[Rate Limiting at Okta]: https://developer.okta.com/docs/api/getting_started/rate-limits\n[okta-library-versioning]: https://developer.okta.com/code/library-versions\n[Rate Limiting at Okta]: https://developer.okta.com/docs/api/getting_started/rate-limits\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fokta%2Fokta-mobile-kotlin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fokta%2Fokta-mobile-kotlin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fokta%2Fokta-mobile-kotlin/lists"}