diff --git a/docs/website/android/introduction.md b/docs/website/android/introduction.md index 6ef53d5..d995a7e 100644 --- a/docs/website/android/introduction.md +++ b/docs/website/android/introduction.md @@ -57,6 +57,8 @@ This SDK assists you in creating custom login flows directly within the applicat ```groovy android.defaultConfig.manifestPlaceholders = [ - 'appAuthRedirectScheme': 'wso2sample' // [!code highlight] + 'appAuthRedirectScheme': 'wso2sample',// [!code highlight] + 'callbackUriHost': '' // [!code highlight], + 'callbackUriScheme': '' // [!code highlight] ] ``` diff --git a/docs/website/android/logout.md b/docs/website/android/logout.md index ef23263..8ff1e1e 100644 --- a/docs/website/android/logout.md +++ b/docs/website/android/logout.md @@ -23,3 +23,6 @@ If you want to perform a logout, you can call the `logout` function in the [!NOTE] +> The `logout` function is a suspend function. Therefore, you need to call it inside a coroutine. diff --git a/docs/website/android/start.md b/docs/website/android/start.md index 4894897..1d828ae 100644 --- a/docs/website/android/start.md +++ b/docs/website/android/start.md @@ -62,10 +62,10 @@ After that, you can call `authenticationProvider.isLoggedInStateFlow`, this will ```kotlin @Composable internal fun LandingScreen() { - val state = authenticationProvider.getAuthenticationStateFlow() + val authenticationStateFlow = authenticationProvider.getAuthenticationStateFlow() - handleAuthenticationState(state) isLoggedInStateFlow() + handleAuthenticationState(authenticationStateFlow) } private fun isLoggedInStateFlow() { @@ -74,7 +74,7 @@ private fun isLoggedInStateFlow() { } } -private fun handleAuthenticationState(state: AuthenticationState) { +private fun handleAuthenticationState(authenticationStateFlow: SharedFlow) { GlobalScope.launch { state.collect { when (it) { @@ -101,6 +101,7 @@ private fun handleAuthenticationState(state: AuthenticationState) { * Gets called when /authn responds with an “SUCCESS” state. This means * authentication flow is completed */ + onSuccessfulLogin() } is AuthenticationState.Loading -> { @@ -112,6 +113,9 @@ private fun handleAuthenticationState(state: AuthenticationState) { } ``` +> [!NOTE] +> You cannot directly use Composable functions inside a coroutine, above its used to show the flow of the application. The best approach you can take is to use [navigation](https://developer.android.com/guide/navigation). + Assuming that you have configured Username and Password as the first authentication step and TOTP as the second step, you can develop the UI as follows using the AuthenticatorTypes provided by the SDK to populate the login form. ```kotlin /** @@ -125,11 +129,11 @@ internal fun LoginForm( authenticationFlow.nextStep.authenticators.forEach { when (it.authenticator) { AuthenticatorTypes.BASIC_AUTHENTICATOR.authenticatorType -> { // [!code highlight] - BasicAuth(authenticatorType = it) + BasicAuth(authenticator = it) } AuthenticatorTypes.TOTP_AUTHENTICATOR.authenticatorType -> { // [!code highlight] - TotpAuth(authenticatorType = it) + TotpAuth(authenticator = it) } } } @@ -142,10 +146,14 @@ In the BasicAuth component you can call the authentication function provided by internal fun BasicAuth(authenticator: Authenticator) { BasicAuthComponent( onLoginClick = { username, password -> - authenticationProvider.authenticateWithUsernameAndPassword( // [!code highlight] - username = username, - password = password - ) + GlobalScope.launch { + authenticationProvider.authenticateWithUsernameAndPassword( + context = context, + authenticatorId = authenticator.authenticatorId, + username = username, + password = password + ) + } } ) } @@ -157,15 +165,16 @@ fun BasicAuthComponent( Column() { var username by remember { mutableStateOf("") } var password by remember { mutableStateOf("") } + OutlinedTextField( value = username, onValueChange = { username = it }, - label = "Username" + label = { Text(text = "Username") } ) OutlinedTextField( value = password, onValueChange = { password = it }, - label = "Password" + label = { Text(text = "Password") } ) Button(onClick = { onLoginClick(username, password) }) { Text(text = "Login") @@ -175,3 +184,8 @@ fun BasicAuthComponent( ``` You will not need to handle the authentication state in multiple places, you can do it at the start of the application, and it will handle the state accordingly. + +> [!CAUTION] +> When using `GlobalScope`, make sure to cancel the coroutine when the composable is removed from the screen. This is to avoid memory leaks. +> Also instead of using `GlobalScope`, you can use `viewModelScope` if you are using the MVVM pattern in your application. +> For more information on how to handle coroutines in Jetpack Compose, see [the following documentation](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/). \ No newline at end of file diff --git a/docs/website/android/token-information.md b/docs/website/android/token-information.md index 51398af..2ea603a 100644 --- a/docs/website/android/token-information.md +++ b/docs/website/android/token-information.md @@ -43,3 +43,6 @@ tokenProvider.performAction(context) { accessToken, idToken, -> action(accessToken, idToken) } ``` + +> [!NOTE] +> All the functions mentioned above are suspend functions. Therefore, you need to call them inside a coroutine. diff --git a/docs/website/android/use-authenticators.md b/docs/website/android/use-authenticators.md index 0bb3458..8216d18 100644 --- a/docs/website/android/use-authenticators.md +++ b/docs/website/android/use-authenticators.md @@ -208,6 +208,6 @@ authenticationProvider.authenticateWithMicrosoftRedirect( ```kotlin authenticationProvider.authenticateWithOpenIdConnect( context, - authenticatorId = authenticator.authenticatorId + authenticatorId = authenticator.authenticatorId ) ``` diff --git a/docs/website/android/user-details.md b/docs/website/android/user-details.md index 2ed287d..aa2eeca 100644 --- a/docs/website/android/user-details.md +++ b/docs/website/android/user-details.md @@ -21,9 +21,9 @@ After the user is authenticated, to get user-related information, we can use the following function. This will return the user details in a `LinkedHashMap`. ```kotlin -coroutineScope.launch { +GlobalScope.launch { runCatching { - authenticationProvider.getUserDetails() // [!code highlight] + authenticationProvider.getBasicUserInfo() // [!code highlight] }.onSuccess { userDetails -> Profile(userDetails) }.onFailure { e -> @@ -31,3 +31,11 @@ coroutineScope.launch { } } ``` + +> [!NOTE] +> You cannot directly use Composable functions inside a coroutine, above its used to show the flow of the application. You can use the `getBasicUserInfo` function in a ViewModel or a Repository and observe the result in the Composable function. + +> [!CAUTION] +> When using `GlobalScope`, make sure to cancel the coroutine when the composable is removed from the screen. This is to avoid memory leaks. +> Also instead of using `GlobalScope`, you can use `viewModelScope` if you are using the MVVM pattern in your application. +> For more information on how to handle coroutines in Jetpack Compose, see [the following documentation](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/). \ No newline at end of file