fix: Return a proper 401 respnose on auth fail

This commit is contained in:
Peter Vacho 2024-12-23 17:32:45 +01:00
parent ec86f48954
commit 07620e7875
Signed by: school
GPG key ID: 8CFC3837052871B4

View file

@ -38,45 +38,57 @@ class AuthInterceptor(
return chain.proceed(originalRequest)
}
// No point in continuing if our refresh token expired, make the user to re-login
if (tokenManager.refreshToken == null || tokenManager.isRefreshTokenExpired()) {
handleFail()
}
try {
refreshAccessTokenIfNeeded()
// Override the original request and add the access token, which should be
// available & non-expired after the above checks (though it's still possible
// that it was invalidated through other means, so we can still fail here).
val requestBuilder = originalRequest.newBuilder()
requestBuilder.addHeader("Authorization", "Bearer $tokenManager.accessToken")
val response = chain.proceed(requestBuilder.build())
// Handle authentication failure, if it occurs
if (response.code() == 401) {
// Clear the access token, as it didn't work anyways, we got 401 with it
tokenManager.clearAccessToken()
// This will definitely trigger a refresh now, as we cleared the access token
refreshAccessTokenIfNeeded()
// Retry the original request with the refreshed access token
val newBuilder = originalRequest.newBuilder()
newBuilder.addHeader("Authorization", "Bearer ${tokenManager.accessToken}")
val newResponse = chain.proceed(newBuilder.build())
// If this request also lead to a 401, something is very wrong, as the access token
// was in fact refreshed by now, which means our refresh token does work, but the
// access token it gave us wasn't valid.
if (newResponse.code() == 401) {
Log.e("API", "Got 403 from a freshly refreshed access token: $newResponse")
throw IllegalStateException("Got 403 from a freshly refreshed access token")
// No point in continuing if our refresh token expired, make the user to re-login
if (tokenManager.refreshToken == null || tokenManager.isRefreshTokenExpired()) {
handleFail()
}
newResponse
}
refreshAccessTokenIfNeeded()
return response
// Override the original request and add the access token, which should be
// available & non-expired after the above checks (though it's still possible
// that it was invalidated through other means, so we can still fail here).
val requestBuilder = originalRequest.newBuilder()
requestBuilder.addHeader("Authorization", "Bearer $tokenManager.accessToken")
val response = chain.proceed(requestBuilder.build())
// Handle authentication failure, if it occurs
if (response.code() == 401) {
// Clear the access token, as it didn't work anyways, we got 401 with it
tokenManager.clearAccessToken()
// This will definitely trigger a refresh now, as we cleared the access token
refreshAccessTokenIfNeeded()
// Retry the original request with the refreshed access token
val newBuilder = originalRequest.newBuilder()
newBuilder.addHeader("Authorization", "Bearer ${tokenManager.accessToken}")
val newResponse = chain.proceed(newBuilder.build())
// If this request also lead to a 401, something is very wrong, as the access token
// was in fact refreshed by now, which means our refresh token does work, but the
// access token it gave us wasn't valid.
if (newResponse.code() == 401) {
Log.e("API", "Got 403 from a freshly refreshed access token: $newResponse")
throw IllegalStateException("Got 403 from a freshly refreshed access token")
}
return newResponse
}
return response
} catch (e: CancellationException) {
// Return an error response to gracefully end the request
return Response.Builder()
.request(chain.request())
.protocol(Protocol.HTTP_1_1)
.code(401)
.message("Session expired")
.body(ResponseBody.create(null, "Session expired"))
.build()
}
}
@Synchronized // Avoid simultaneous refresh attempts