Skip to content

Commit

Permalink
add option to specify hosted/embedded mode from build.gradle file
Browse files Browse the repository at this point in the history
  • Loading branch information
frontegg-david committed Oct 12, 2023
1 parent b023c37 commit affbf58
Show file tree
Hide file tree
Showing 18 changed files with 122 additions and 85 deletions.
8 changes: 2 additions & 6 deletions android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,8 @@
<application>

<activity
android:name="com.frontegg.android.embedded.EmbeddedAuthActivity"
android:exported="true" />

<activity
android:name="com.google.androidbrowserhelper.trusted.LauncherActivity"
android:name="${auth_activity}"
android:exported="true">

<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />

Expand All @@ -39,6 +34,7 @@

</intent-filter>
</activity>

<activity
android:name="com.frontegg.android.AuthenticationActivity"
android:exported="true">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import android.net.Uri
import android.os.Bundle
import android.util.Log
import androidx.browser.customtabs.CustomTabsIntent
import com.frontegg.android.embedded.EmbeddedAuthActivity
import com.frontegg.android.utils.AuthorizeUrlGenerator

class AuthenticationActivity : Activity() {
Expand Down Expand Up @@ -59,29 +58,13 @@ class AuthenticationActivity : Activity() {
val code = intent.data?.getQueryParameter("code")
if (code != null) {
Log.d(TAG, "Got intent with oauth callback")
FronteggAuth.instance.isLoading.value = true
FronteggAuth.instance.handleHostedLoginCallback(code)
setResult(RESULT_OK)
finish()
return
}

/**
* due to lake to support from android chrome tab
* we are sharing magic link cookie with the chrome
* instance to give the ability to login via magic link
* in the native chrome browser, then the hosted login
* will redirect the user directly to the application
* with the exchange code to finalize the authorization process
*/
// val path = intentUrl.path
// if(path != null && path.startsWith("/oauth/account/login/magic-link?token=")){
// Log.d(TAG, "Got intent with magic link")
// var url = intentUrl.toString()
// url = url.replace("magic-link?token=", "magic-link?chromeTab=true&token=")
// startAuth(url)
// return
// }

Log.d(TAG, "Got intent with unknown data")
setResult(RESULT_CANCELED)
finish()
Expand Down Expand Up @@ -116,17 +99,13 @@ class AuthenticationActivity : Activity() {
private const val CUSTOM_TAB_LAUNCHED = "com.frontegg.android.CUSTOM_TAB_LAUNCHED"
private val TAG = AuthenticationActivity::class.java.simpleName

fun authenticateUsingBrowser(activity: Activity) {
if (FronteggApp.getInstance().isEmbeddedMode) {
EmbeddedAuthActivity.authenticate(activity)
} else {
val intent = Intent(activity, AuthenticationActivity::class.java)
val authorizeUri = AuthorizeUrlGenerator().generate()
intent.putExtra(AUTH_LAUNCHED, true)
intent.putExtra(AUTHORIZE_URI, authorizeUri.first)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
activity.startActivityForResult(intent, OAUTH_LOGIN_REQUEST)
}
fun authenticate(activity: Activity) {
val intent = Intent(activity, AuthenticationActivity::class.java)
val authorizeUri = AuthorizeUrlGenerator().generate()
intent.putExtra(AUTH_LAUNCHED, true)
intent.putExtra(AUTHORIZE_URI, authorizeUri.first)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
activity.startActivityForResult(intent, OAUTH_LOGIN_REQUEST)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
package com.frontegg.android.embedded
package com.frontegg.android

import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.LinearLayout
import com.frontegg.android.FronteggAuth
import com.frontegg.android.R
import com.frontegg.android.embedded.FronteggWebView
import com.frontegg.android.utils.AuthorizeUrlGenerator
import com.frontegg.android.utils.NullableObject
import io.reactivex.rxjava3.disposables.Disposable
Expand All @@ -26,10 +25,27 @@ class EmbeddedAuthActivity : Activity() {
webView = findViewById(R.id.custom_webview)
loaderLayout = findViewById(R.id.loaderView)

val authorizeUrl = AuthorizeUrlGenerator()
val url = authorizeUrl.generate()
val intentLaunched =
intent.extras?.getBoolean(AUTH_LAUNCHED, false) ?: false

webViewUrl = url.first
if (intentLaunched) {
val url = intent.extras!!.getString(AUTHORIZE_URI)
if (url == null) {
setResult(RESULT_CANCELED)
finish()
return
}
webViewUrl = url
} else {
val intentUrl = intent.data
if (intentUrl == null) {
setResult(RESULT_CANCELED)
finish()
return
}

webViewUrl = intentUrl.toString()
}


if (!FronteggAuth.instance.initializing.value
Expand Down Expand Up @@ -63,6 +79,7 @@ class EmbeddedAuthActivity : Activity() {
setResult(RESULT_OK)
finish()
}

override fun onResume() {
super.onResume()
disposables.add(FronteggAuth.instance.showLoader.subscribe(this.showLoaderConsumer))
Expand All @@ -89,9 +106,9 @@ class EmbeddedAuthActivity : Activity() {

val authorizeUri = AuthorizeUrlGenerator().generate()
intent.putExtra(AUTH_LAUNCHED, true)
// intent.putExtra(AUTHORIZE_URI, authorizeUri.first)
// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
intent.putExtra(AUTHORIZE_URI, authorizeUri.first)
activity.startActivityForResult(intent, OAUTH_LOGIN_REQUEST)
}

}
}
2 changes: 1 addition & 1 deletion android/src/main/java/com/frontegg/android/FronteggApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class FronteggApp private constructor(
val context: Context,
val baseUrl: String,
val clientId: String,
val isEmbeddedMode:Boolean
val isEmbeddedMode:Boolean = true
) {

val credentialManager: CredentialManager = CredentialManager(context)
Expand Down
57 changes: 37 additions & 20 deletions android/src/main/java/com/frontegg/android/FronteggAuth.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import android.os.Handler
import android.os.Looper
import android.util.Log
import android.webkit.CookieManager
import com.frontegg.android.embedded.EmbeddedAuthActivity
import com.frontegg.android.models.User
import com.frontegg.android.services.Api
import com.frontegg.android.services.CredentialManager
Expand All @@ -19,7 +18,6 @@ import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.lang.Exception
import java.time.Instant
import java.util.*
import kotlin.concurrent.schedule
Expand Down Expand Up @@ -87,7 +85,7 @@ class FronteggAuth(
}
}

private fun refreshTokenIfNeeded(): Boolean {
fun refreshTokenIfNeeded(): Boolean {
val refreshToken = this.refreshToken.value ?: return false
Log.d(TAG, "refreshTokenIfNeeded()")

Expand Down Expand Up @@ -158,30 +156,49 @@ class FronteggAuth(
return true
}

private fun getDomainCookie(siteName: String): String {
val cookieManager = CookieManager.getInstance()
return cookieManager.getCookie(siteName);
}


fun logout(callback: () -> Unit = {}) {
CookieManager.getInstance().removeAllCookies {
CookieManager.getInstance().flush()
GlobalScope.launch(Dispatchers.IO) {
refreshTaskRunner?.cancel()
isLoading.value = true
isAuthenticated.value = false
accessToken.value = null
refreshToken.value = null
user.value = null
api.logout()
credentialManager.clear()
val handler = Handler(Looper.getMainLooper())
handler.post {
isLoading.value = false
callback()
}


isLoading.value = true
refreshTaskRunner?.cancel()
GlobalScope.launch(Dispatchers.IO) {

val logoutCookies = getDomainCookie(baseUrl)
val logoutAccessToken = accessToken.value

if (logoutAccessToken != null && FronteggApp.getInstance().isEmbeddedMode) {
api.logout(logoutCookies, logoutAccessToken)
}

isLoading.value = true
isAuthenticated.value = false
accessToken.value = null
refreshToken.value = null
user.value = null
credentialManager.clear()

val handler = Handler(Looper.getMainLooper())
handler.post {
isLoading.value = false
callback()
}

}

}

fun login(activity: Activity) {
AuthenticationActivity.authenticateUsingBrowser(activity)
if (FronteggApp.getInstance().isEmbeddedMode) {
EmbeddedAuthActivity.authenticate(activity)
} else {
AuthenticationActivity.authenticate(activity)
}
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.frontegg.android

import com.google.androidbrowserhelper.trusted.LauncherActivity

class HostedAuthActivity : LauncherActivity()
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ class FronteggWebClient(val context: Context) : WebViewClient() {
return OverrideUrlType.Unknown
}


override fun shouldOverrideUrlLoading(
view: WebView?,
request: WebResourceRequest?
Expand All @@ -151,7 +152,14 @@ class FronteggWebClient(val context: Context) : WebViewClient() {
} else {
return super.shouldOverrideUrlLoading(view, request)
}
}


override fun shouldInterceptRequest(
view: WebView?,
request: WebResourceRequest?
): WebResourceResponse? {
return super.shouldInterceptRequest(view, request)
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ open class FronteggWebView : WebView {
settings.useWideViewPort = true
settings.loadWithOverviewMode = true
settings.domStorageEnabled = true
settings.safeBrowsingEnabled = true

webViewClient = FronteggWebClient(context)
}
Expand Down
32 changes: 23 additions & 9 deletions android/src/main/java/com/frontegg/android/services/Api.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.frontegg.android.services

import android.util.Log
import android.webkit.CookieManager
import com.frontegg.android.models.AuthResponse
import com.frontegg.android.models.User
import com.frontegg.android.utils.ApiConstants
Expand All @@ -16,6 +18,7 @@ import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.IOException
import java.lang.Exception

open class Api(
private var baseUrl: String,
Expand All @@ -24,6 +27,10 @@ open class Api(
) {
private var httpClient: OkHttpClient

companion object {
val TAG: String = Api::class.java.simpleName
}

init {
this.httpClient = OkHttpClient()
}
Expand All @@ -50,14 +57,12 @@ open class Api(

private fun buildPostRequest(
path: String,
body: JsonObject,
body: JsonObject?,
additionalHeaders: Map<String, String> = mapOf()
): Call {
val url = "${this.baseUrl}/$path".toHttpUrl()
val requestBuilder = Request.Builder()
val bodyRequest =
body.toString()
.toRequestBody("application/json; charset=utf-8".toMediaType())
val bodyRequest = body?.toString()?.toRequestBody("application/json; charset=utf-8".toMediaType())
val headers = this.prepareHeaders(additionalHeaders);

requestBuilder.method("POST", bodyRequest)
Expand Down Expand Up @@ -168,16 +173,25 @@ open class Api(
return null
}

fun logout() {
val refreshToken = this.credentialManager.getOrNull(CredentialKeys.ACCESS_TOKEN)
fun logout(cookies: String, accessToken:String) {
try {

if (refreshToken != null) {
val call = buildPostRequest(
ApiConstants.logout, JsonObject(), mapOf(
Pair("fe_refresh_$clientId", refreshToken)
Pair("authorization", "Bearer $accessToken"),
Pair("cookie", cookies),
Pair("accept", "*/*"),
Pair("content-type", "application/json"),
Pair("origin", baseUrl),
Pair("referer","$baseUrl/oauth/account/logout")
)
)
call.execute()
val res = call.execute()


Log.d(TAG, "logged out, ${res.body?.string()}")
} catch (e: Exception) {
Log.e(TAG, "Failed to logout user", e)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ class AuthorizeUrlGenerator {
val url = authorizeUrlBuilder.build().toString()
Log.d(TAG, "Generated url: $url")


val authorizeUrl = Uri.Builder()
.encodedPath(baseUrl)
.appendEncodedPath("frontegg/oauth/logout")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class ApiConstants {
const val tenants: String = "identity/resources/users/v3/me/tenants"
const val refreshToken: String = "oauth/token"
const val exchangeToken: String = "oauth/token"
const val logout: String = "identity/resources/auth/v1/logout"
const val logout: String = "frontegg/identity/resources/auth/v1/logout"
const val switchTenant: String = "identity/resources/users/v1/tenant"


Expand Down
2 changes: 1 addition & 1 deletion android/src/main/res/layout/activity_embedded_auth.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".embedded.EmbeddedAuthActivity">
tools:context=".EmbeddedAuthActivity">


<com.frontegg.android.embedded.FronteggWebView
Expand Down
Loading

0 comments on commit affbf58

Please sign in to comment.