@@ -73,51 +73,54 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
7373 }
7474
7575 /* *
76- * Stores the given [SSOCredentials] refresh token in the storage.
77- * This method must be called if the SSOCredentials are obtained by directly invoking [AuthenticationAPIClient.fetchSessionToken] api and
78- * [rotating refresh token](https://auth0.com/docs/secure/tokens/refresh-tokens/refresh-token-rotation) are enabled for
79- * the client. Method will silently return ,if the passed credentials has no refresh token.
76+ * Creates a new request to exchange a refresh token for a session transfer token that can be used to perform web single sign-on.
8077 *
81- * @param ssoCredentials the credentials to save in the storage.
78+ * When opening your website on any browser or web view, add the session transfer token to the URL as a query
79+ * parameter. Then your website can redirect the user to Auth0's `/authorize` endpoint, passing along the query
80+ * parameter with the session transfer token. For example,
81+ * `https://example.com/login?session_transfer_token=THE_TOKEN`.
82+ *
83+ * It will fail with [CredentialsManagerException] if the existing refresh_token is null or no longer valid.
84+ * This method will handle saving the refresh_token, if a new one is issued.
8285 */
83- override fun saveSsoCredentials (ssoCredentials : SSOCredentials ) {
84- if (ssoCredentials.refreshToken.isNullOrEmpty())
85- return // No refresh token to save
86- serialExecutor.execute {
87- val existingRefreshToken = storage.retrieveString(KEY_REFRESH_TOKEN )
88- // Checking if the existing one needs to be replaced with the new one
89- if (ssoCredentials.refreshToken == existingRefreshToken)
90- return @execute
91- storage.store(KEY_REFRESH_TOKEN , ssoCredentials.refreshToken)
92- }
86+ override fun getSsoCredentials (callback : Callback <SSOCredentials , CredentialsManagerException >) {
87+ getSsoCredentials(emptyMap(), callback)
9388 }
9489
9590 /* *
96- * Fetches a new [SSOCredentials] . It will fail with [CredentialsManagerException]
97- * if the existing refresh_token is null or no longer valid. This method will handle saving the refresh_token,
98- * if a new one is issued
91+ * Creates a new request to exchange a refresh token for a session transfer token that can be used to perform web single sign-on.
92+ *
93+ * When opening your website on any browser or web view, add the session transfer token to the URL as a query
94+ * parameter. Then your website can redirect the user to Auth0's `/authorize` endpoint, passing along the query
95+ * parameter with the session transfer token. For example,
96+ * `https://example.com/login?session_transfer_token=THE_TOKEN`.
97+ *
98+ * It will fail with [CredentialsManagerException] if the existing refresh_token is null or no longer valid.
99+ * This method will handle saving the refresh_token, if a new one is issued.
99100 */
100- override fun getSsoCredentials (callback : Callback <SSOCredentials , CredentialsManagerException >) {
101+ override fun getSsoCredentials (
102+ parameters : Map <String , String >,
103+ callback : Callback <SSOCredentials , CredentialsManagerException >
104+ ) {
101105 serialExecutor.execute {
102106 val refreshToken = storage.retrieveString(KEY_REFRESH_TOKEN )
103107 if (refreshToken.isNullOrEmpty()) {
104108 callback.onFailure(CredentialsManagerException .NO_REFRESH_TOKEN )
105109 return @execute
106110 }
107111
112+ val request = authenticationClient.ssoExchange(refreshToken)
108113 try {
109- val sessionCredentials =
110- authenticationClient.fetchSessionToken(refreshToken)
111- .execute()
112- saveSsoCredentials(sessionCredentials)
113- callback.onSuccess(sessionCredentials)
114+ if (parameters.isNotEmpty()) {
115+ request.addParameters(parameters)
116+ }
117+ val sessionTransferCredentials = request.execute()
118+ saveSsoCredentials(sessionTransferCredentials)
119+ callback.onSuccess(sessionTransferCredentials)
114120 } catch (error: AuthenticationException ) {
115121 val exception = when {
116- error.isRefreshTokenDeleted ||
117- error.isInvalidRefreshToken -> CredentialsManagerException .Code .RENEW_FAILED
118-
119122 error.isNetworkError -> CredentialsManagerException .Code .NO_NETWORK
120- else -> CredentialsManagerException .Code .API_ERROR
123+ else -> CredentialsManagerException .Code .SSO_EXCHANGE_FAILED
121124 }
122125 callback.onFailure(
123126 CredentialsManagerException (
@@ -130,23 +133,48 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
130133 }
131134
132135 /* *
133- * Fetches a new [SSOCredentials] . It will fail with [CredentialsManagerException]
134- * if the existing refresh_token is null or no longer valid. This method will handle saving the refresh_token,
135- * if a new one is issued
136+ * Creates a new request to exchange a refresh token for a session transfer token that can be used to perform web single sign-on.
137+ *
138+ * When opening your website on any browser or web view, add the session transfer token to the URL as a query
139+ * parameter. Then your website can redirect the user to Auth0's `/authorize` endpoint, passing along the query
140+ * parameter with the session transfer token. For example,
141+ * `https://example.com/login?session_transfer_token=THE_TOKEN`.
142+ *
143+ * It will fail with [CredentialsManagerException] if the existing refresh_token is null or no longer valid.
144+ * This method will handle saving the refresh_token, if a new one is issued.
136145 */
137146 @JvmSynthetic
138147 @Throws(CredentialsManagerException ::class )
139148 override suspend fun awaitSsoCredentials (): SSOCredentials {
149+ return awaitSsoCredentials(emptyMap())
150+ }
151+
152+ /* *
153+ * Creates a new request to exchange a refresh token for a session transfer token that can be used to perform web single sign-on.
154+ *
155+ * When opening your website on any browser or web view, add the session transfer token to the URL as a query
156+ * parameter. Then your website can redirect the user to Auth0's `/authorize` endpoint, passing along the query
157+ * parameter with the session transfer token. For example,
158+ * `https://example.com/login?session_transfer_token=THE_TOKEN`.
159+ *
160+ * It will fail with [CredentialsManagerException] if the existing refresh_token is null or no longer valid.
161+ * This method will handle saving the refresh_token, if a new one is issued.
162+ */
163+ @JvmSynthetic
164+ @Throws(CredentialsManagerException ::class )
165+ override suspend fun awaitSsoCredentials (parameters : Map <String , String >): SSOCredentials {
140166 return suspendCancellableCoroutine { continuation ->
141- getSsoCredentials(object : Callback <SSOCredentials , CredentialsManagerException > {
142- override fun onSuccess (result : SSOCredentials ) {
143- continuation.resume(result)
144- }
167+ getSsoCredentials(
168+ parameters,
169+ object : Callback <SSOCredentials , CredentialsManagerException > {
170+ override fun onSuccess (result : SSOCredentials ) {
171+ continuation.resume(result)
172+ }
145173
146- override fun onFailure (error : CredentialsManagerException ) {
147- continuation.resumeWithException(error)
148- }
149- })
174+ override fun onFailure (error : CredentialsManagerException ) {
175+ continuation.resumeWithException(error)
176+ }
177+ })
150178 }
151179 }
152180
@@ -241,7 +269,8 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
241269 forceRefresh : Boolean
242270 ): Credentials {
243271 return suspendCancellableCoroutine { continuation ->
244- getCredentials(scope,
272+ getCredentials(
273+ scope,
245274 minTtl,
246275 parameters,
247276 headers,
@@ -614,6 +643,24 @@ public class CredentialsManager @VisibleForTesting(otherwise = VisibleForTesting
614643 storage.remove(audience)
615644 }
616645
646+ /* *
647+ * Helper method to store the given [SSOCredentials] refresh token in the storage.
648+ * Method will silently return if the passed credentials have no refresh token.
649+ *
650+ * @param ssoCredentials the credentials to save in the storage.
651+ */
652+ @VisibleForTesting(otherwise = VisibleForTesting .PRIVATE )
653+ internal fun saveSsoCredentials (ssoCredentials : SSOCredentials ) {
654+ storage.store(KEY_ID_TOKEN , ssoCredentials.idToken)
655+ val existingRefreshToken = storage.retrieveString(KEY_REFRESH_TOKEN )
656+ // Checking if the existing one needs to be replaced with the new one
657+ if (ssoCredentials.refreshToken.isNullOrEmpty())
658+ return // No refresh token to save
659+ if (ssoCredentials.refreshToken == existingRefreshToken)
660+ return // Same refresh token, no need to save
661+ storage.store(KEY_REFRESH_TOKEN , ssoCredentials.refreshToken)
662+ }
663+
617664 @VisibleForTesting(otherwise = VisibleForTesting .PRIVATE )
618665 internal fun recreateCredentials (
619666 idToken : String ,
0 commit comments