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

Integration of Okta Authentication with Custom Login Screen #207

Open
chowdarym05 opened this issue Sep 24, 2024 · 3 comments
Open

Integration of Okta Authentication with Custom Login Screen #207

chowdarym05 opened this issue Sep 24, 2024 · 3 comments
Labels
enhancement New feature or request

Comments

@chowdarym05
Copy link

Describe the feature request?

am currently working on integrating Okta authentication into our company application. After reviewing the dynamic app example provided in the Okta IDX Android GitHub repository, I noticed that it displays its own login screens for user authentication.

However, I would like to retain our existing login screen and implement Okta authentication in the background. My goal is to allow users to enter their username and password on our custom UI while still leveraging Okta’s authentication services.

Could you please provide guidance on how to achieve this?

New or Affected Resource(s)

Android Application Developers

Provide a documentation link

No response

Additional Information?

Specifically, I’m looking for insights on:

How to bypass the default login screens provided by the Okta SDK.
How to programmatically authenticate users using Okta with the credentials collected from our custom login screen.

@chowdarym05 chowdarym05 added the enhancement New feature or request label Sep 24, 2024
@rajdeepnanua-okta
Copy link
Contributor

Hi @chowdarym05, here is a small sample I adopted from okta-idx-swift's basic login sample:

class BasicLogin {
    val flow: InteractionCodeFlow = InteractionCodeFlow()

    suspend fun login(username: String, password: String): OAuth2ClientResult<Token> {
        // Starts authentication, getting the first initial response. This
        // usually is a prompt to input the user's identifier (username), and
        // depending on policy settings, may also include a field for the user's
        // password.
        when (flow.start(redirectUri = Uri.parse(BuildConfig.REDIRECT_URI))) {
            is OAuth2ClientResult.Error -> TODO("Error case")
            else -> {
                // Do nothing
            }
        }

        var result = flow.resume()

        while (result is OAuth2ClientResult.Success && !result.result.isLoginSuccessful) {
            val response = result.result
            if (response.messages.messages.isNotEmpty()) {
                throw Exception(response.messages.messages[0].message)
            }

            // Look for username remediation and proceed, then do the same for password in the next iteration
            response.remediations.get(IdxRemediation.Type.IDENTIFY)?.let { usernameRemediation ->
                val usernameField =
                    usernameRemediation["identifier"] ?: throw Exception("No username field")
                usernameField.value = username
                result = flow.proceed(usernameRemediation)
            } ?: run {
                val passwordRemediation =
                    response.remediations.get(IdxRemediation.Type.CHALLENGE_AUTHENTICATOR)
                        ?: throw Exception("No username or password field")
                if (passwordRemediation.authenticators.get(IdxAuthenticator.Kind.PASSWORD) == null) throw Exception(
                    "Unexpected authenticator"
                )
                val passwordField = passwordRemediation["credentials.passcode"]
                    ?: throw Exception("No password field in password remediation")
                passwordField.value = password
                result = flow.proceed(passwordRemediation)
            }
        }

        val response = result.getOrThrow()
        if (response.isLoginSuccessful) {
            return flow.exchangeInteractionCodeForTokens(response.remediations[IdxRemediation.Type.ISSUE]!!)
        } else {
            throw Exception("Something went wrong")
        }
    }
}

Let me know if this helps with your use case. I will look to adding this sample into this repository for smoother experience

@chowdarym05
Copy link
Author

Hi Rajdeep, Thanks alot for the code snippet.
I am able to successfully implement okta login.

I am working on logout using credential.revokeToken(RevokeTokenType.ACCESS_TOKEN), and token refreshing part.
I am facing an issue here. 

I am trying to store access token using Credential.default = Credential.store(result.result)
But getting below exception:
java.lang.UnsatisfiedLinkError: dlopen failed: library "libsqlcipher.so" not found


Screenshot 2024-10-09 at 2 36 59 PM

Any suggestion here would be appreciated

@rajdeepnanua-okta
Copy link
Contributor

rajdeepnanua-okta commented Oct 10, 2024

Hi @chowdarym05, I wasn't able to reproduce this issue, but I found a similar issue reported on stackoverflow: https://stackoverflow.com/questions/70987929/java-lang-unsatisfiedlinkerror-after-changing-minsdkversion

The suggested fix is to use useLegacyPackaging = true in your app's build.gradle. Could you also list your minSdk, targetSdk, and compileSdk details? Maybe that will help me with reproducing this issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants