Skip to content

Commit

Permalink
Merge pull request #23 from frontegg/FR-14813-custom-sso-fixes
Browse files Browse the repository at this point in the history
FR-14813 - SDK improvements
  • Loading branch information
frontegg-david authored Jan 8, 2024
2 parents 1e201dd + 6ceff78 commit 962205d
Show file tree
Hide file tree
Showing 12 changed files with 220 additions and 48 deletions.
28 changes: 18 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ from [Frontegg Portal Domain](https://portal.frontegg.com/development/settings/d

- Navigate to [Login Method Settings](https://portal.frontegg.com/development/authentication/hosted)
- Toggle Hosted login method
- Add `{{ANDROID_PACKAGE_NAME}}://{{FRONTEGG_BASE_URL}}/ios/oauth/callback`
- Add `{{ANDROID_PACKAGE_NAME}}://{{FRONTEGG_BASE_URL}}/android/oauth/callback` **(without assetlinks)**
- Add `https://{{FRONTEGG_BASE_URL}}/{{ANDROID_PACKAGE_NAME}}/android/oauth/callback` **(required for assetlinks)**
- Replace `ANDROID_PACKAGE_NAME` with your application identifier
- Replace `FRONTEGG_BASE_URL` with your Frontegg base url

Expand Down Expand Up @@ -319,9 +320,11 @@ Follow [Config Android AssetLinks](#config-android-assetlinks) to add your Andro

The first domain will be placed automatically in the `AndroidManifest.xml` file. For each additional region, you will
need to add an `intent-filter`.
Replace `${FRONTEGG_DOMAIN_2}` with the second domain from the previous step.

NOTE: if you are using `Custom Chrome Tab` you have to use `android:name` `com.frontegg.android.HostedAuthActivity` instead of `com.frontegg.android.EmbeddedAuthActivity`


```xml

<application>
Expand All @@ -334,13 +337,15 @@ NOTE: if you are using `Custom Chrome Tab` you have to use `android:name` `com.f
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="https" />
<!-- Modify second domain -->
<data android:host="{{FRONTEGG_DOMAIN_2}}" />
<data android:pathPrefix="/oauth/account/activate" />
<data android:pathPrefix="/oauth/account/invitation/accept" />
<data android:pathPrefix="/oauth/account/reset-password" />
<data android:pathPrefix="/oauth/account/social/success" />
<data android:pathPrefix="/oauth/account/login/magic-link" />
<!-- DONT NOT COMBINE THE FOLLOWING LINES INTO ONE LINE-->
<data android:host="${FRONTEGG_DOMAIN_2}"
android:pathPrefix="/oauth/account/activate" />
<data android:host="${FRONTEGG_DOMAIN_2}"
android:pathPrefix="/oauth/account/invitation/accept" />
<data android:host="${FRONTEGG_DOMAIN_2}"
android:pathPrefix="/oauth/account/reset-password" />
<data android:host="${FRONTEGG_DOMAIN_2}"
android:pathPrefix="/oauth/account/login/magic-link" />
</intent-filter>
</activity>

Expand All @@ -352,8 +357,11 @@ NOTE: if you are using `Custom Chrome Tab` you have to use `android:name` `com.f
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<!-- Modify second domain -->
<data android:host="davidprod.frontegg.com" android:scheme="${package_name}" />
<!-- DONT NOT COMBINE THE FOLLOWING LINES INTO ONE LINE-->
<data android:host="${FRONTEGG_DOMAIN_2}" android:scheme="${package_name}" />
<data android:host="${FRONTEGG_DOMAIN_2}"
android:pathPrefix="/${package_name}/android/oauth/callback"
android:scheme="https" />
</intent-filter>
</activity>
</application>
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {


group 'com.frontegg.android'
version '1.2.2'
version '1.2.3'


android {
Expand Down
31 changes: 23 additions & 8 deletions android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
Expand All @@ -16,12 +17,22 @@
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="https" />
<data android:host="${frontegg_domain}" />
<data android:pathPrefix="/oauth/account/activate" />
<data android:pathPrefix="/oauth/account/invitation/accept" />
<data android:pathPrefix="/oauth/account/reset-password" />
<data android:pathPrefix="/oauth/account/social/success" />
<data android:pathPrefix="/oauth/account/login/magic-link" />
<!-- DONT NOT COMBINE THE FOLLOWING LINES INTO ONE LINE-->
<data
android:host="${frontegg_domain}"
android:pathPrefix="/oauth/account/activate" />
<data
android:host="${frontegg_domain}"
android:pathPrefix="/oauth/account/invitation/accept" />
<data
android:host="${frontegg_domain}"
android:pathPrefix="/oauth/account/reset-password" />
<data
android:host="${frontegg_domain}"
android:pathPrefix="/oauth/account/social/success" />
<data
android:host="${frontegg_domain}"
android:pathPrefix="/oauth/account/login/magic-link" />
</intent-filter>
</activity>

Expand Down Expand Up @@ -65,13 +76,17 @@
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<!-- DONT NOT COMBINE THE FOLLOWING LINES INTO ONE LINE-->
<data
android:host="${frontegg_domain}"
android:scheme="${package_name}" />
<data
android:host="${frontegg_domain}"
android:pathPrefix="/${package_name}/android/oauth/callback"
android:scheme="https" />
</intent-filter>
</activity>


</application>
<queries>
<intent>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class AuthenticationActivity : Activity() {
if (code != null) {
Log.d(TAG, "Got intent with oauth callback")
FronteggAuth.instance.isLoading.value = true
FronteggAuth.instance.handleHostedLoginCallback(code)
FronteggAuth.instance.handleHostedLoginCallback(code, null, this)
setResult(RESULT_OK)
finish()
return
Expand Down
29 changes: 20 additions & 9 deletions android/src/main/java/com/frontegg/android/FronteggApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@ import android.content.pm.PackageManager.MATCH_ALL
import android.util.Log
import com.frontegg.android.exceptions.FronteggException
import com.frontegg.android.exceptions.FronteggException.Companion.FRONTEGG_APP_MUST_BE_INITIALIZED
import com.frontegg.android.exceptions.FronteggException.Companion.FRONTEGG_DOMAIN_MUST_NOT_START_WITH_HTTPS
import com.frontegg.android.regions.RegionConfig
import com.frontegg.android.services.*
import java.lang.RuntimeException

class FronteggApp private constructor(
val context: Context,
Expand All @@ -19,8 +17,9 @@ class FronteggApp private constructor(
val isEmbeddedMode: Boolean = true,
val regions: List<RegionConfig> = listOf(),
val selectedRegion: RegionConfig? = null,
val handleLoginWithSocialLogin: Boolean = true,
val handleLoginWithSSO: Boolean = false
var handleLoginWithSocialLogin: Boolean = true,
var handleLoginWithSSO: Boolean = false,
val useAssetsLinks: Boolean = false,
) {

val credentialManager: CredentialManager = CredentialManager(context)
Expand All @@ -45,19 +44,30 @@ class FronteggApp private constructor(
public fun init(
fronteggDomain: String,
clientId: String,
context: Context
context: Context,
useAssetsLinks: Boolean = false
) {
val baseUrl: String = if (fronteggDomain.startsWith("https")) {
throw FronteggException(FRONTEGG_DOMAIN_MUST_NOT_START_WITH_HTTPS)
fronteggDomain
} else {
"https://$fronteggDomain"
}

val isEmbeddedMode = isActivityEnabled(context, EmbeddedAuthActivity::class.java.name)
instance = FronteggApp(context, baseUrl, clientId, isEmbeddedMode)
instance = FronteggApp(
context,
baseUrl,
clientId,
isEmbeddedMode,
useAssetsLinks = useAssetsLinks
)
}

public fun initWithRegions(regions: List<RegionConfig>, context: Context): FronteggApp {
public fun initWithRegions(
regions: List<RegionConfig>,
context: Context,
useAssetsLinks: Boolean = false
): FronteggApp {

val isEmbeddedMode = isActivityEnabled(context, EmbeddedAuthActivity::class.java.name)
val selectedRegion = CredentialManager(context).getSelectedRegion()
Expand All @@ -71,7 +81,8 @@ class FronteggApp private constructor(
regionConfig.clientId,
isEmbeddedMode,
regions,
regionConfig
regionConfig,
useAssetsLinks = useAssetsLinks
)
instance = newInstance
return newInstance
Expand Down
4 changes: 3 additions & 1 deletion android/src/main/java/com/frontegg/android/FronteggAuth.kt
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ class FronteggAuth(
this.initializing.value = false
}

fun handleHostedLoginCallback(code: String, webView: WebView? = null): Boolean {
fun handleHostedLoginCallback(code: String, webView: WebView? = null, activity: Activity? = null): Boolean {

val codeVerifier = credentialManager.getCodeVerifier()
val redirectUrl = Constants.oauthCallbackUrl(baseUrl)
Expand All @@ -194,6 +194,8 @@ class FronteggAuth(
Handler(Looper.getMainLooper()).post {
webView.loadUrl(url.first)
}
}else if (activity != null){
login(activity)
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@ import android.net.Uri
import android.net.UrlQuerySanitizer
import android.os.Handler
import android.os.Looper
import android.text.Html
import android.util.Base64
import android.util.Log
import android.webkit.*
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
import com.frontegg.android.FronteggApp
import com.frontegg.android.FronteggAuth
import com.frontegg.android.utils.AuthorizeUrlGenerator
import com.frontegg.android.utils.Constants
import com.frontegg.android.utils.Constants.Companion.loginRoutes
import com.frontegg.android.utils.Constants.Companion.socialLoginRedirectUrl
import com.frontegg.android.utils.Constants.Companion.successLoginRoutes
import com.google.gson.Gson
import com.frontegg.android.utils.generateErrorPage
import com.google.gson.JsonParser
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -54,10 +60,13 @@ class FronteggWebClient(val context: Context) : WebViewClient() {
FronteggAuth.instance.isLoading.value = true
}


if (url?.startsWith("data:text/html,") == true) {
FronteggAuth.instance.isLoading.value = false
return
}

val fronteggApp = FronteggApp.getInstance()
val nativeModuleFunctions = JSONObject()
val nativeModuleFunctions = JSONObject()
nativeModuleFunctions.put("loginWithSocialLogin", fronteggApp.handleLoginWithSocialLogin)
nativeModuleFunctions.put("loginWithSSO", fronteggApp.handleLoginWithSSO)
val jsObject = nativeModuleFunctions.toString()
Expand All @@ -70,9 +79,60 @@ class FronteggWebClient(val context: Context) : WebViewClient() {
request: WebResourceRequest?,
error: WebResourceError?
) {

try {
val errorMessage = "Check your internet connection and try again."
val htmlError = Html.escapeHtml(errorMessage)
val errorPage = generateErrorPage(
htmlError,
error = error?.description?.toString(),
url = request?.url?.toString()
)
val encodedHtml = Base64.encodeToString(errorPage.toByteArray(), Base64.NO_PADDING)
Handler(Looper.getMainLooper()).post {
view?.loadData(encodedHtml, "text/html", "base64")
}
} catch (e: Exception) {
// ignore error
}
Log.e(TAG, "onReceivedError: ${error?.description}")
super.onReceivedError(view, request, error)
}

private fun checkIfFronteggError(view: WebView?, url: String?, status: Int? = null) {
if (view == null || url == null) {
return
}
view.evaluateJavascript("document.body.innerText") { result ->
try {
var text = result
if (text == null) {
return@evaluateJavascript
}
var json = JsonParser.parseString(text)
while (!json.isJsonObject) {
text = json.asString
json = JsonParser.parseString(text)
}
val error = json.asJsonObject.get("errors").asJsonArray.map {
it.asString
}.joinToString("\n")

Log.e(TAG, "Frontegg ERROR: $error")

val htmlError = Html.escapeHtml(error)
val errorPage = generateErrorPage(htmlError, status = status)
val encodedHtml = Base64.encodeToString(errorPage.toByteArray(), Base64.NO_PADDING)
Handler(Looper.getMainLooper()).post {
view.loadData(encodedHtml, "text/html", "base64")
}

} catch (e: Exception) {
// ignore error
}
}
}

override fun onReceivedHttpError(
view: WebView?,
request: WebResourceRequest?,
Expand All @@ -83,6 +143,7 @@ class FronteggWebClient(val context: Context) : WebViewClient() {
} else {
Log.d(TAG, "onReceivedHttpError: HTTP api call, ${request?.url?.path}")
}
checkIfFronteggError(view, request?.url.toString(), errorResponse?.statusCode)
super.onReceivedHttpError(view, request, errorResponse)
}

Expand Down Expand Up @@ -217,7 +278,10 @@ class FronteggWebClient(val context: Context) : WebViewClient() {
}

@OptIn(DelicateCoroutinesApi::class)
private fun setSocialLoginRedirectUri(@Suppress("UNUSED_PARAMETER") webView: WebView, uri: Uri): Boolean {
private fun setSocialLoginRedirectUri(
@Suppress("UNUSED_PARAMETER") webView: WebView,
uri: Uri
): Boolean {
Log.d(TAG, "setSocialLoginRedirectUri setting redirect uri for social login")

if (uri.getQueryParameter("redirectUri") != null) {
Expand Down
12 changes: 8 additions & 4 deletions android/src/main/java/com/frontegg/android/utils/Constants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ class ApiConstants {
class Constants {

companion object {

val successLoginRoutes = listOf(
"/oauth/account/social/success",
)
Expand All @@ -29,9 +28,14 @@ class Constants {
fun oauthCallbackUrl(baseUrl: String): String {

val host = baseUrl.substring("https://".length)
val packageName = FronteggApp.getInstance().packageName

return "${packageName}://${host}/android/oauth/callback"
val app = FronteggApp.getInstance();
val packageName = app.packageName
val useAssetsLinks = app.useAssetsLinks
return if (useAssetsLinks) {
"https://${host}/${packageName}/android/oauth/callback"
} else {
"${packageName}://${host}/android/oauth/callback"
}
}

fun socialLoginRedirectUrl(baseUrl: String): String {
Expand Down
Loading

0 comments on commit 962205d

Please sign in to comment.