Skip to content

Commit 0940eed

Browse files
FR-22335
Session updates for refresh token lifetime Added ability to disable token refreshing in SDK-side
1 parent ae02607 commit 0940eed

File tree

14 files changed

+596
-65
lines changed

14 files changed

+596
-65
lines changed

android/src/main/java/com/frontegg/android/FronteggApp.kt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ val Context.fronteggApp: FronteggApp
6868
mainActivityClass = mainClassActivityClass,
6969
deepLinkScheme = constants.deepLinkScheme,
7070
useDiskCacheWebview = constants.useDiskCacheWebview,
71+
disableAutoRefresh = constants.disableAutoRefresh,
7172
)
7273
}
7374

@@ -119,6 +120,7 @@ interface FronteggApp {
119120
* @param useChromeCustomTabs Whether the Frontegg SDK should use Chrome Custom Tabs (default: `false`).
120121
* @param mainActivityClass The Activity to navigate to after authorization (default: `null`).
121122
* @param useDiskCacheWebview Whether the Frontegg SDK should use disk cache for WebView (default: `false`).
123+
* @param disableAutoRefresh Whether to disable automatic token refresh (default: `false`).
122124
*/
123125
@VisibleForTesting
124126
internal fun init(
@@ -131,6 +133,7 @@ interface FronteggApp {
131133
mainActivityClass: Class<*>? = null,
132134
deepLinkScheme: String? = null,
133135
useDiskCacheWebview: Boolean = false,
136+
disableAutoRefresh: Boolean = false,
134137
) {
135138
val baseUrl: String = if (fronteggDomain.startsWith("https")) {
136139
fronteggDomain
@@ -150,7 +153,8 @@ interface FronteggApp {
150153
useAssetsLinks = useAssetsLinks,
151154
useChromeCustomTabs = useChromeCustomTabs,
152155
mainActivityClass = mainActivityClass,
153-
useDiskCacheWebview = useDiskCacheWebview
156+
useDiskCacheWebview = useDiskCacheWebview,
157+
disableAutoRefresh = disableAutoRefresh
154158
)
155159
runDebugChecksSafe(context, fronteggDomain, clientId)
156160
}
@@ -164,6 +168,7 @@ interface FronteggApp {
164168
* @param useChromeCustomTabs Whether the Frontegg SDK should use Chrome Custom Tabs (default: `false`).
165169
* @param mainActivityClass The Activity to navigate to after authorization (default: `null`).
166170
* @param useDiskCacheWebview Whether the Frontegg SDK should use disk cache for WebView (default: `false`).
171+
* @param disableAutoRefresh Whether to disable automatic token refresh (default: `false`).
167172
*/
168173
fun initWithRegions(
169174
regions: List<RegionConfig>,
@@ -172,6 +177,7 @@ interface FronteggApp {
172177
useChromeCustomTabs: Boolean = false,
173178
mainActivityClass: Class<*>? = null,
174179
useDiskCacheWebview: Boolean = false,
180+
disableAutoRefresh: Boolean = false,
175181
): FronteggApp {
176182

177183
val isEmbeddedMode = context.isActivityEnabled(EmbeddedAuthActivity::class.java.name)
@@ -191,7 +197,8 @@ interface FronteggApp {
191197
useAssetsLinks = useAssetsLinks,
192198
useChromeCustomTabs = useChromeCustomTabs,
193199
mainActivityClass = mainActivityClass,
194-
useDiskCacheWebview = useDiskCacheWebview
200+
useDiskCacheWebview = useDiskCacheWebview,
201+
disableAutoRefresh = disableAutoRefresh
195202
)
196203
instance = newInstance
197204

@@ -210,7 +217,8 @@ interface FronteggApp {
210217
useAssetsLinks = useAssetsLinks,
211218
useChromeCustomTabs = useChromeCustomTabs,
212219
mainActivityClass = mainActivityClass,
213-
useDiskCacheWebview = useDiskCacheWebview
220+
useDiskCacheWebview = useDiskCacheWebview,
221+
disableAutoRefresh = disableAutoRefresh
214222
)
215223
instance = newInstance
216224
// Persist parameters to allow retry when network becomes available

android/src/main/java/com/frontegg/android/FronteggAuth.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ interface FronteggAuth {
114114
*/
115115
fun refreshTokenIfNeeded(): Boolean
116116

117+
/**
118+
* Process queued requests when network becomes available.
119+
*/
120+
fun processQueuedRequests()
121+
117122
/**
118123
* Login with passkeys
119124
* @param activity is the activity of application;

android/src/main/java/com/frontegg/android/models/FronteggConstants.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ data class FronteggConstants(
99
val deepLinkScheme: String?,
1010
val useDiskCacheWebview: Boolean,
1111
val mainActivityClass: String?,
12+
val disableAutoRefresh: Boolean,
1213
) {
1314
fun toMap(): Map<String, Any?> {
1415
return mapOf(
@@ -20,6 +21,7 @@ data class FronteggConstants(
2021
Pair("deepLinkScheme", deepLinkScheme),
2122
Pair("useDiskCacheWebview", useDiskCacheWebview),
2223
Pair("mainActivityClass", mainActivityClass),
24+
Pair("disableAutoRefresh", disableAutoRefresh),
2325
)
2426
}
2527
}

android/src/main/java/com/frontegg/android/services/Api.kt

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,11 @@ open class Api(
4848
if (!fromSelected.isNullOrBlank()) return fromSelected
4949
return storage.regions.firstOrNull()?.baseUrl ?: ""
5050
}
51+
52+
/**
53+
* Get the base URL for network probing
54+
*/
55+
fun getServerUrl(): String = baseUrl
5156
private val clientId: String
5257
get() {
5358
val direct = storage.clientId
@@ -173,12 +178,37 @@ open class Api(
173178
return this.httpClient.newCall(request)
174179
}
175180

181+
private fun buildGetRequestWithTimeout(path: String, timeoutMs: Long): Call {
182+
val url = if (path.startsWith("http")) {
183+
path.toHttpUrl()
184+
} else {
185+
"$baseUrl/$path".toHttpUrl()
186+
}
187+
val requestBuilder = Request.Builder()
188+
val headers = prepareHeaders()
189+
190+
requestBuilder.method("GET", null)
191+
requestBuilder.headers(headers)
192+
requestBuilder.url(url)
193+
194+
val request = requestBuilder.build()
195+
196+
// Create client with increased timeout
197+
val clientWithTimeout = httpClient.newBuilder()
198+
.connectTimeout(timeoutMs, java.util.concurrent.TimeUnit.MILLISECONDS)
199+
.readTimeout(timeoutMs, java.util.concurrent.TimeUnit.MILLISECONDS)
200+
.writeTimeout(timeoutMs, java.util.concurrent.TimeUnit.MILLISECONDS)
201+
.build()
202+
203+
return clientWithTimeout.newCall(request)
204+
}
205+
176206

177207
@Throws(IllegalArgumentException::class, IOException::class)
178208
fun me(): User? {
179-
val meCall = buildGetRequest(ApiConstants.me)
209+
val meCall = buildGetRequestWithTimeout(ApiConstants.me, 120000)
180210
val meResponse = meCall.execute()
181-
val tenantsCall = buildGetRequest(ApiConstants.tenants)
211+
val tenantsCall = buildGetRequestWithTimeout(ApiConstants.tenants, 120000)
182212
val tenantsResponse = tenantsCall.execute()
183213

184214
if (meResponse.isSuccessful && tenantsResponse.isSuccessful) {
@@ -189,32 +219,42 @@ open class Api(
189219
val meJsonStr = meResponse.body!!.string()
190220
val tenantsJsonStr = tenantsResponse.body!!.string()
191221

222+
Log.d(TAG, "api.me() successful - me length: ${meJsonStr.length}, tenants length: ${tenantsJsonStr.length}")
223+
192224
val meJson: MutableMap<String, Any> = gson.fromJson(meJsonStr, mapType)
193225
val tenantsJson: MutableMap<String, Any> = gson.fromJson(tenantsJsonStr, mapType)
194226

195227
meJson["tenants"] = tenantsJson["tenants"] as Any
196228
meJson["activeTenant"] = tenantsJson["activeTenant"] as Any
197229

198230
val merged = Gson().toJson(meJson)
199-
return Gson().fromJson(merged, User::class.java)
231+
val user = Gson().fromJson(merged, User::class.java)
232+
Log.d(TAG, "api.me() returning user: ${user != null}")
233+
return user
234+
} else {
235+
Log.w(TAG, "api.me() failed - me: ${meResponse.code} ${meResponse.message}, tenants: ${tenantsResponse.code} ${tenantsResponse.message}")
200236
}
201237

202238
return null
203239
}
204240

205241
@Throws(IllegalArgumentException::class, IOException::class, FailedToAuthenticateException::class)
206242
fun refreshToken(refreshToken: String): AuthResponse {
243+
Log.d(TAG, "Starting refresh token request")
207244
val body = JsonObject()
208245
body.addProperty("grant_type", "refresh_token")
209246
body.addProperty("refresh_token", refreshToken)
210247

211-
// Use shorter timeout like Swift version (5 seconds)
212-
val call = buildPostRequestWithTimeout(ApiConstants.refreshToken, body, 5000)
248+
// Use reasonable timeout for refresh token (30 seconds)
249+
val call = buildPostRequestWithTimeout(ApiConstants.refreshToken, body, 30000)
213250

251+
Log.d(TAG, "Executing refresh token request...")
214252
val response = call.execute()
253+
Log.d(TAG, "Refresh token response received: code=${response.code}")
215254

216255
if (response.isSuccessful) {
217256
val responseBody = response.body!!.string()
257+
Log.d(TAG, "Refresh token successful, parsing response")
218258
return Gson().fromJson(responseBody, AuthResponse::class.java)
219259
}
220260

android/src/main/java/com/frontegg/android/services/FronteggAppService.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ class FronteggAppService(
2626
private var useChromeCustomTabs: Boolean = false,
2727
private var mainActivityClass: Class<*>? = null,
2828
private var deepLinkScheme: String? = null,
29-
private var useDiskCacheWebview: Boolean = false
29+
private var useDiskCacheWebview: Boolean = false,
30+
private var disableAutoRefresh: Boolean = false
3031
) : FronteggApp {
3132

3233
private val storage = StorageProvider.getInnerStorage()
@@ -43,7 +44,8 @@ class FronteggAppService(
4344
FronteggAuthService(
4445
credentialManager,
4546
appLifecycle,
46-
refreshTokenManager
47+
refreshTokenManager,
48+
disableAutoRefresh = disableAutoRefresh
4749
)
4850
}
4951

0 commit comments

Comments
 (0)