Skip to content

Commit 6f5e847

Browse files
authored
Merge branch 'main' into SDK-5778
2 parents 66ddabd + f801aff commit 6f5e847

File tree

7 files changed

+250
-2
lines changed

7 files changed

+250
-2
lines changed

EXAMPLES.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
- [Sign Up with a database connection](#sign-up-with-a-database-connection)
1919
- [Get user information](#get-user-information)
2020
- [Custom Token Exchange](#custom-token-exchange)
21-
- [Native to Web SSO login](#native-to-web-sso-login)
21+
- [Native to Web SSO login [EA]](#native-to-web-sso-login-ea)
2222
- [Credentials Manager](#credentials-manager)
2323
- [Secure Credentials Manager](#secure-credentials-manager)
2424
- [Usage](#usage)
@@ -541,7 +541,11 @@ authentication
541541
</details>
542542

543543

544-
## Native to Web SSO login
544+
## Native to Web SSO login [EA]
545+
546+
> [!NOTE]
547+
> This feature is currently available in [Early Access](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages#early-access). Please reach out to Auth0 support to get it
548+
> enabled for your tenant.
545549
546550
This feature allows you to authenticate a user in a web session using the refresh token obtained from the native session without requiring the user to log in again.
547551

auth0/src/main/java/com/auth0/android/authentication/AuthenticationAPIClient.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,12 @@ public class AuthenticationAPIClient @VisibleForTesting(otherwise = VisibleForTe
945945
* parameter with the session transfer token. For example,
946946
* `https://example.com/login?session_transfer_token=THE_TOKEN`.
947947
*
948+
* ##Availability
949+
*
950+
* This feature is currently available in
951+
* [Early Access](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages#early-access).
952+
* Please reach out to Auth0 support to get it enabled for your tenant.
953+
*
948954
*
949955
* @param refreshToken A valid refresh token obtained as part of Auth0 authentication
950956
* @return a request to fetch a session transfer token

auth0/src/main/java/com/auth0/android/authentication/storage/CredentialsManager.kt

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.auth0.android.authentication.storage
22

33
import android.text.TextUtils
4+
import android.util.Log
45
import androidx.annotation.VisibleForTesting
56
import com.auth0.android.authentication.AuthenticationAPIClient
67
import com.auth0.android.authentication.AuthenticationException
@@ -80,6 +81,12 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
8081
* parameter with the session transfer token. For example,
8182
* `https://example.com/login?session_transfer_token=THE_TOKEN`.
8283
*
84+
* ## Availability
85+
*
86+
* This feature is currently available in
87+
* [Early Access](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages#early-access).
88+
* Please reach out to Auth0 support to get it enabled for your tenant.
89+
*
8390
* It will fail with [CredentialsManagerException] if the existing refresh_token is null or no longer valid.
8491
* This method will handle saving the refresh_token, if a new one is issued.
8592
*/
@@ -95,6 +102,12 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
95102
* parameter with the session transfer token. For example,
96103
* `https://example.com/login?session_transfer_token=THE_TOKEN`.
97104
*
105+
* ## Availability
106+
*
107+
* This feature is currently available in
108+
* [Early Access](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages#early-access).
109+
* Please reach out to Auth0 support to get it enabled for your tenant.
110+
*
98111
* It will fail with [CredentialsManagerException] if the existing refresh_token is null or no longer valid.
99112
* This method will handle saving the refresh_token, if a new one is issued.
100113
*/
@@ -128,6 +141,17 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
128141
error
129142
)
130143
)
144+
} catch (exception: RuntimeException) {
145+
Log.e(
146+
TAG,
147+
"Caught unexpected exceptions while fetching sso token ${exception.stackTraceToString()}"
148+
)
149+
callback.onFailure(
150+
CredentialsManagerException(
151+
CredentialsManagerException.Code.UNKNOWN_ERROR,
152+
exception
153+
)
154+
)
131155
}
132156
}
133157
}
@@ -140,6 +164,12 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
140164
* parameter with the session transfer token. For example,
141165
* `https://example.com/login?session_transfer_token=THE_TOKEN`.
142166
*
167+
* ## Availability
168+
*
169+
* This feature is currently available in
170+
* [Early Access](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages#early-access).
171+
* Please reach out to Auth0 support to get it enabled for your tenant.
172+
*
143173
* It will fail with [CredentialsManagerException] if the existing refresh_token is null or no longer valid.
144174
* This method will handle saving the refresh_token, if a new one is issued.
145175
*/
@@ -157,6 +187,12 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
157187
* parameter with the session transfer token. For example,
158188
* `https://example.com/login?session_transfer_token=THE_TOKEN`.
159189
*
190+
* ## Availability
191+
*
192+
* This feature is currently available in
193+
* [Early Access](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages#early-access).
194+
* Please reach out to Auth0 support to get it enabled for your tenant.
195+
*
160196
* It will fail with [CredentialsManagerException] if the existing refresh_token is null or no longer valid.
161197
* This method will handle saving the refresh_token, if a new one is issued.
162198
*/
@@ -499,6 +535,20 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
499535
exception, error
500536
)
501537
)
538+
} catch (exception: RuntimeException) {
539+
/**
540+
* Catching any unexpected runtime errors in the token renewal flow
541+
*/
542+
Log.e(
543+
TAG,
544+
"Caught unexpected exceptions for token renewal ${exception.stackTraceToString()}"
545+
)
546+
callback.onFailure(
547+
CredentialsManagerException(
548+
CredentialsManagerException.Code.UNKNOWN_ERROR,
549+
exception
550+
)
551+
)
502552
}
503553
}
504554
}
@@ -684,5 +734,6 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
684734
// This is no longer used as we get the credentials expiry from the access token only,
685735
// but we still store it so users can rollback to versions where it is required.
686736
private const val LEGACY_KEY_CACHE_EXPIRES_AT = "com.auth0.cache_expires_at"
737+
private val TAG = CredentialsManager::class.java.simpleName
687738
}
688739
}

auth0/src/main/java/com/auth0/android/authentication/storage/CredentialsManagerException.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public class CredentialsManagerException :
4646
NO_NETWORK,
4747
API_ERROR,
4848
SSO_EXCHANGE_FAILED,
49+
UNKNOWN_ERROR
4950
}
5051

5152
private var code: Code?
@@ -146,6 +147,8 @@ public class CredentialsManagerException :
146147
public val SSO_EXCHANGE_FAILED: CredentialsManagerException =
147148
CredentialsManagerException(Code.SSO_EXCHANGE_FAILED)
148149

150+
public val UNKNOWN_ERROR: CredentialsManagerException = CredentialsManagerException(Code.UNKNOWN_ERROR)
151+
149152

150153
private fun getMessage(code: Code): String {
151154
return when (code) {
@@ -191,6 +194,7 @@ public class CredentialsManagerException :
191194
Code.NO_NETWORK -> "Failed to execute the network request."
192195
Code.API_ERROR -> "An error occurred while processing the request."
193196
Code.SSO_EXCHANGE_FAILED ->"The exchange of the refresh token for SSO credentials failed."
197+
Code.UNKNOWN_ERROR -> "An unknown error has occurred while fetching the token. Please check the error cause for more details."
194198
}
195199
}
196200
}

auth0/src/main/java/com/auth0/android/authentication/storage/SecureCredentialsManager.kt

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,12 @@ public class SecureCredentialsManager @VisibleForTesting(otherwise = VisibleForT
164164
* parameter with the session transfer token. For example,
165165
* `https://example.com/login?session_transfer_token=THE_TOKEN`.
166166
*
167+
* ## Availability
168+
*
169+
* This feature is currently available in
170+
* [Early Access](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages#early-access).
171+
* Please reach out to Auth0 support to get it enabled for your tenant.
172+
*
167173
* It will fail with [CredentialsManagerException] if the existing refresh_token is null or no longer valid.
168174
* This method will handle saving the refresh_token, if a new one is issued.
169175
*/
@@ -179,6 +185,12 @@ public class SecureCredentialsManager @VisibleForTesting(otherwise = VisibleForT
179185
* parameter with the session transfer token. For example,
180186
* `https://example.com/login?session_transfer_token=THE_TOKEN`.
181187
*
188+
* ## Availability
189+
*
190+
* This feature is currently available in
191+
* [Early Access](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages#early-access).
192+
* Please reach out to Auth0 support to get it enabled for your tenant.
193+
*
182194
* It will fail with [CredentialsManagerException] if the existing refresh_token is null or no longer valid.
183195
* This method will handle saving the refresh_token, if a new one is issued.
184196
*/
@@ -223,6 +235,17 @@ public class SecureCredentialsManager @VisibleForTesting(otherwise = VisibleForT
223235
CredentialsManagerException.Code.STORE_FAILED, error
224236
)
225237
callback.onFailure(exception)
238+
} catch (exception: RuntimeException) {
239+
Log.e(
240+
TAG,
241+
"Caught unexpected exceptions while fetching sso token ${exception.stackTraceToString()}"
242+
)
243+
callback.onFailure(
244+
CredentialsManagerException(
245+
CredentialsManagerException.Code.UNKNOWN_ERROR,
246+
exception
247+
)
248+
)
226249
}
227250
}
228251
}
@@ -235,6 +258,12 @@ public class SecureCredentialsManager @VisibleForTesting(otherwise = VisibleForT
235258
* parameter with the session transfer token. For example,
236259
* `https://example.com/login?session_transfer_token=THE_TOKEN`.
237260
*
261+
* ## Availability
262+
*
263+
* This feature is currently available in
264+
* [Early Access](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages#early-access).
265+
* Please reach out to Auth0 support to get it enabled for your tenant.
266+
*
238267
* It will fail with [CredentialsManagerException] if the existing refresh_token is null or no longer valid.
239268
* This method will handle saving the refresh_token, if a new one is issued.
240269
*/
@@ -252,6 +281,12 @@ public class SecureCredentialsManager @VisibleForTesting(otherwise = VisibleForT
252281
* parameter with the session transfer token. For example,
253282
* `https://example.com/login?session_transfer_token=THE_TOKEN`.
254283
*
284+
* ## Availability
285+
*
286+
* This feature is currently available in
287+
* [Early Access](https://auth0.com/docs/troubleshoot/product-lifecycle/product-release-stages#early-access).
288+
* Please reach out to Auth0 support to get it enabled for your tenant.
289+
*
255290
* It will fail with [CredentialsManagerException] if the existing refresh_token is null or no longer valid.
256291
* This method will handle saving the refresh_token, if a new one is issued.
257292
*/
@@ -801,6 +836,21 @@ public class SecureCredentialsManager @VisibleForTesting(otherwise = VisibleForT
801836
)
802837
)
803838
return@execute
839+
} catch (exception: RuntimeException) {
840+
/**
841+
* Catching any unexpected runtime errors in the token renewal flow
842+
*/
843+
Log.e(
844+
TAG,
845+
"Caught unexpected exceptions for token renewal ${exception.stackTraceToString()}"
846+
)
847+
callback.onFailure(
848+
CredentialsManagerException(
849+
CredentialsManagerException.Code.UNKNOWN_ERROR,
850+
exception
851+
)
852+
)
853+
return@execute
804854
}
805855

806856
try {

auth0/src/test/java/com/auth0/android/authentication/storage/CredentialsManagerTest.kt

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,31 @@ public class CredentialsManagerTest {
356356
)
357357
}
358358

359+
@Test
360+
public fun shouldFailOnGetNewSSOCredentialsWhenUnexpectedErrorOccurs() {
361+
Mockito.`when`(storage.retrieveString("com.auth0.refresh_token")).thenReturn("refreshToken")
362+
Mockito.`when`(
363+
client.ssoExchange("refreshToken")
364+
).thenReturn(SSOCredentialsRequest)
365+
//Trigger failure
366+
val runtimeException = RuntimeException(
367+
"unexpected_error"
368+
)
369+
Mockito.`when`(SSOCredentialsRequest.execute()).thenThrow(runtimeException)
370+
manager.getSsoCredentials(ssoCallback)
371+
verify(ssoCallback).onFailure(
372+
exceptionCaptor.capture()
373+
)
374+
val exception = exceptionCaptor.firstValue
375+
MatcherAssert.assertThat(exception, Is.`is`(Matchers.notNullValue()))
376+
MatcherAssert.assertThat(exception, Is.`is`(CredentialsManagerException.UNKNOWN_ERROR))
377+
MatcherAssert.assertThat(exception.cause, Is.`is`(runtimeException))
378+
MatcherAssert.assertThat(
379+
exception.message,
380+
Is.`is`("An unknown error has occurred while fetching the token. Please check the error cause for more details.")
381+
)
382+
}
383+
359384
@Test
360385
@ExperimentalCoroutinesApi
361386
public fun shouldFailOnAwaitSSOCredentialsWhenNoRefreshTokenWasSaved(): Unit = runTest {
@@ -1448,6 +1473,46 @@ public class CredentialsManagerTest {
14481473
)
14491474
}
14501475

1476+
@Test
1477+
public fun shouldGetAndFailToRenewExpiredCredentialsWhenAnyUnexpectedErrorOccurs() {
1478+
Mockito.`when`(storage.retrieveString("com.auth0.id_token")).thenReturn("idToken")
1479+
Mockito.`when`(storage.retrieveString("com.auth0.access_token")).thenReturn("accessToken")
1480+
Mockito.`when`(storage.retrieveString("com.auth0.refresh_token")).thenReturn("refreshToken")
1481+
Mockito.`when`(storage.retrieveString("com.auth0.token_type")).thenReturn("type")
1482+
val expirationTime = CredentialsMock.CURRENT_TIME_MS //Same as current time --> expired
1483+
Mockito.`when`(storage.retrieveLong("com.auth0.expires_at")).thenReturn(expirationTime)
1484+
Mockito.`when`(storage.retrieveLong("com.auth0.cache_expires_at"))
1485+
.thenReturn(expirationTime)
1486+
Mockito.`when`(storage.retrieveString("com.auth0.scope")).thenReturn("scope")
1487+
Mockito.`when`(
1488+
client.renewAuth("refreshToken")
1489+
).thenReturn(request)
1490+
//Trigger failure
1491+
val runtimeException = NullPointerException("Something went wrong")
1492+
Mockito.`when`(request.execute()).thenThrow(runtimeException)
1493+
manager.getCredentials(callback)
1494+
verify(storage, never())
1495+
.store(ArgumentMatchers.anyString(), ArgumentMatchers.anyInt())
1496+
verify(storage, never())
1497+
.store(ArgumentMatchers.anyString(), ArgumentMatchers.anyLong())
1498+
verify(storage, never())
1499+
.store(ArgumentMatchers.anyString(), ArgumentMatchers.anyString())
1500+
verify(storage, never())
1501+
.store(ArgumentMatchers.anyString(), ArgumentMatchers.anyBoolean())
1502+
verify(storage, never()).remove(ArgumentMatchers.anyString())
1503+
verify(callback).onFailure(
1504+
exceptionCaptor.capture()
1505+
)
1506+
val exception = exceptionCaptor.firstValue
1507+
MatcherAssert.assertThat(exception, Is.`is`(Matchers.notNullValue()))
1508+
MatcherAssert.assertThat(exception, Is.`is`(CredentialsManagerException.UNKNOWN_ERROR))
1509+
MatcherAssert.assertThat(exception.cause, Is.`is`(runtimeException))
1510+
MatcherAssert.assertThat(
1511+
exception.message,
1512+
Is.`is`("An unknown error has occurred while fetching the token. Please check the error cause for more details.")
1513+
)
1514+
}
1515+
14511516
@Test
14521517
public fun shouldClearCredentials() {
14531518
manager.clearCredentials()

0 commit comments

Comments
 (0)