@@ -54,53 +54,55 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
5454 storage.store(LEGACY_KEY_CACHE_EXPIRES_AT , credentials.expiresAt.time)
5555 }
5656
57-
5857 /* *
59- * Stores the given [SSOCredentials] refresh token in the storage.
60- * This method must be called if the SSOCredentials are obtained by directly invoking [AuthenticationAPIClient.fetchSessionToken] api and
61- * [rotating refresh token](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation) are enabled for
62- * the client. Method will silently return ,if the passed credentials has no refresh token.
58+ * Creates a new request to exchange a refresh token for a session transfer token that can be used to perform web single sign-on.
6359 *
64- * @param ssoCredentials the credentials to save in the storage.
60+ * When opening your website on any browser or web view, add the session transfer token to the URL as a query
61+ * parameter. Then your website can redirect the user to Auth0's `/authorize` endpoint, passing along the query
62+ * parameter with the session transfer token. For example,
63+ * `https://example.com/login?session_transfer_token=THE_TOKEN`.
64+ *
65+ * It will fail with [CredentialsManagerException] if the existing refresh_token is null or no longer valid.
66+ * This method will handle saving the refresh_token, if a new one is issued.
6567 */
66- override fun saveSsoCredentials (ssoCredentials : SSOCredentials ) {
67- if (ssoCredentials.refreshToken.isNullOrEmpty())
68- return // No refresh token to save
69- serialExecutor.execute {
70- val existingRefreshToken = storage.retrieveString(KEY_REFRESH_TOKEN )
71- // Checking if the existing one needs to be replaced with the new one
72- if (ssoCredentials.refreshToken == existingRefreshToken)
73- return @execute
74- storage.store(KEY_REFRESH_TOKEN , ssoCredentials.refreshToken)
75- }
68+ override fun getSsoCredentials (callback : Callback <SSOCredentials , CredentialsManagerException >) {
69+ getSsoCredentials(emptyMap(), callback)
7670 }
7771
7872 /* *
79- * Fetches a new [SSOCredentials] . It will fail with [CredentialsManagerException]
80- * if the existing refresh_token is null or no longer valid. This method will handle saving the refresh_token,
81- * if a new one is issued
73+ * Creates a new request to exchange a refresh token for a session transfer token that can be used to perform web single sign-on.
74+ *
75+ * When opening your website on any browser or web view, add the session transfer token to the URL as a query
76+ * parameter. Then your website can redirect the user to Auth0's `/authorize` endpoint, passing along the query
77+ * parameter with the session transfer token. For example,
78+ * `https://example.com/login?session_transfer_token=THE_TOKEN`.
79+ *
80+ * It will fail with [CredentialsManagerException] if the existing refresh_token is null or no longer valid.
81+ * This method will handle saving the refresh_token, if a new one is issued.
8282 */
83- override fun getSsoCredentials (callback : Callback <SSOCredentials , CredentialsManagerException >) {
83+ override fun getSsoCredentials (
84+ parameters : Map <String , String >,
85+ callback : Callback <SSOCredentials , CredentialsManagerException >
86+ ) {
8487 serialExecutor.execute {
8588 val refreshToken = storage.retrieveString(KEY_REFRESH_TOKEN )
8689 if (refreshToken.isNullOrEmpty()) {
8790 callback.onFailure(CredentialsManagerException .NO_REFRESH_TOKEN )
8891 return @execute
8992 }
9093
94+ val request = authenticationClient.ssoExchange(refreshToken)
9195 try {
92- val sessionCredentials =
93- authenticationClient.fetchSessionToken(refreshToken)
94- .execute()
95- saveSsoCredentials(sessionCredentials)
96- callback.onSuccess(sessionCredentials)
96+ if (parameters.isNotEmpty()) {
97+ request.addParameters(parameters)
98+ }
99+ val sessionTransferCredentials = request.execute()
100+ saveSsoCredentials(sessionTransferCredentials)
101+ callback.onSuccess(sessionTransferCredentials)
97102 } catch (error: AuthenticationException ) {
98103 val exception = when {
99- error.isRefreshTokenDeleted ||
100- error.isInvalidRefreshToken -> CredentialsManagerException .Code .RENEW_FAILED
101-
102104 error.isNetworkError -> CredentialsManagerException .Code .NO_NETWORK
103- else -> CredentialsManagerException .Code .API_ERROR
105+ else -> CredentialsManagerException .Code .SSO_EXCHANGE_FAILED
104106 }
105107 callback.onFailure(
106108 CredentialsManagerException (
@@ -113,23 +115,48 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
113115 }
114116
115117 /* *
116- * Fetches a new [SSOCredentials] . It will fail with [CredentialsManagerException]
117- * if the existing refresh_token is null or no longer valid. This method will handle saving the refresh_token,
118- * if a new one is issued
118+ * Creates a new request to exchange a refresh token for a session transfer token that can be used to perform web single sign-on.
119+ *
120+ * When opening your website on any browser or web view, add the session transfer token to the URL as a query
121+ * parameter. Then your website can redirect the user to Auth0's `/authorize` endpoint, passing along the query
122+ * parameter with the session transfer token. For example,
123+ * `https://example.com/login?session_transfer_token=THE_TOKEN`.
124+ *
125+ * It will fail with [CredentialsManagerException] if the existing refresh_token is null or no longer valid.
126+ * This method will handle saving the refresh_token, if a new one is issued.
119127 */
120128 @JvmSynthetic
121129 @Throws(CredentialsManagerException ::class )
122130 override suspend fun awaitSsoCredentials (): SSOCredentials {
131+ return awaitSsoCredentials(emptyMap())
132+ }
133+
134+ /* *
135+ * Creates a new request to exchange a refresh token for a session transfer token that can be used to perform web single sign-on.
136+ *
137+ * When opening your website on any browser or web view, add the session transfer token to the URL as a query
138+ * parameter. Then your website can redirect the user to Auth0's `/authorize` endpoint, passing along the query
139+ * parameter with the session transfer token. For example,
140+ * `https://example.com/login?session_transfer_token=THE_TOKEN`.
141+ *
142+ * It will fail with [CredentialsManagerException] if the existing refresh_token is null or no longer valid.
143+ * This method will handle saving the refresh_token, if a new one is issued.
144+ */
145+ @JvmSynthetic
146+ @Throws(CredentialsManagerException ::class )
147+ override suspend fun awaitSsoCredentials (parameters : Map <String , String >): SSOCredentials {
123148 return suspendCancellableCoroutine { continuation ->
124- getSsoCredentials(object : Callback <SSOCredentials , CredentialsManagerException > {
125- override fun onSuccess (result : SSOCredentials ) {
126- continuation.resume(result)
127- }
149+ getSsoCredentials(
150+ parameters,
151+ object : Callback <SSOCredentials , CredentialsManagerException > {
152+ override fun onSuccess (result : SSOCredentials ) {
153+ continuation.resume(result)
154+ }
128155
129- override fun onFailure (error : CredentialsManagerException ) {
130- continuation.resumeWithException(error)
131- }
132- })
156+ override fun onFailure (error : CredentialsManagerException ) {
157+ continuation.resumeWithException(error)
158+ }
159+ })
133160 }
134161 }
135162
@@ -224,7 +251,8 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
224251 forceRefresh : Boolean
225252 ): Credentials {
226253 return suspendCancellableCoroutine { continuation ->
227- getCredentials(scope,
254+ getCredentials(
255+ scope,
228256 minTtl,
229257 parameters,
230258 headers,
@@ -458,6 +486,24 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
458486 storage.remove(LEGACY_KEY_CACHE_EXPIRES_AT )
459487 }
460488
489+ /* *
490+ * Helper method to store the given [SSOCredentials] refresh token in the storage.
491+ * Method will silently return if the passed credentials have no refresh token.
492+ *
493+ * @param ssoCredentials the credentials to save in the storage.
494+ */
495+ @VisibleForTesting(otherwise = VisibleForTesting .PRIVATE )
496+ internal fun saveSsoCredentials (ssoCredentials : SSOCredentials ) {
497+ storage.store(KEY_ID_TOKEN , ssoCredentials.idToken)
498+ val existingRefreshToken = storage.retrieveString(KEY_REFRESH_TOKEN )
499+ // Checking if the existing one needs to be replaced with the new one
500+ if (ssoCredentials.refreshToken.isNullOrEmpty())
501+ return // No refresh token to save
502+ if (ssoCredentials.refreshToken == existingRefreshToken)
503+ return // Same refresh token, no need to save
504+ storage.store(KEY_REFRESH_TOKEN , ssoCredentials.refreshToken)
505+ }
506+
461507 @VisibleForTesting(otherwise = VisibleForTesting .PRIVATE )
462508 internal fun recreateCredentials (
463509 idToken : String ,
0 commit comments