bugfix/fix-refresh-token-error (#668)

* when backend returns 401 also remove cookies and redirect in frontend if cookies are not set w/ burnettk

* added a copule helpful comments w/ burnettk

---------

Co-authored-by: jasquat <jasquat@users.noreply.github.com>
This commit is contained in:
jasquat 2023-11-14 14:54:16 -05:00 committed by GitHub
parent 6136a51c85
commit 18207bcfbd
4 changed files with 39 additions and 12 deletions

View File

@ -152,6 +152,7 @@ def login_return(code: str, state: str, session_state: str = "") -> Response | N
tld.new_authentication_identifier = authentication_identifier
return redirect(redirect_url)
# we normally clear cookies on 401, but there is a high chance you do not have any yet in this case
raise ApiError(
error_code="invalid_login",
message="Login failed. Please try again",
@ -159,6 +160,7 @@ def login_return(code: str, state: str, session_state: str = "") -> Response | N
)
else:
# we normally clear cookies on 401, but there is a high chance you do not have any yet in this case
current_app.logger.error(f"id_token not found in payload from provider: {auth_token_object}")
raise ApiError(
error_code="invalid_token",
@ -208,8 +210,7 @@ def login_api_return(code: str, state: str, session_state: str) -> str:
def logout(id_token: str, authentication_identifier: str, redirect_url: str | None) -> Response:
if redirect_url is None:
redirect_url = ""
tld = current_app.config["THREAD_LOCAL_DATA"]
tld.user_has_logged_out = True
AuthenticationService.set_user_has_logged_out()
return AuthenticationService().logout(
redirect_url=redirect_url, id_token=id_token, authentication_identifier=authentication_identifier
)
@ -296,8 +297,7 @@ def _force_logout_user_if_necessary(user_model: UserModel | None = None) -> bool
and user_model.service_id == "spiff_guest_service_id"
and not AuthorizationService.request_allows_guest_access()
):
tld = current_app.config["THREAD_LOCAL_DATA"]
tld.user_has_logged_out = True
AuthenticationService.set_user_has_logged_out()
return True
return False
@ -377,6 +377,7 @@ def _get_user_model_from_token(token: str) -> UserModel | None:
}
if user_info is None:
AuthenticationService.set_user_has_logged_out()
raise ApiError(
error_code="invalid_token",
message="Your token is expired. Please Login",
@ -384,6 +385,7 @@ def _get_user_model_from_token(token: str) -> UserModel | None:
) from token_expired_error
except Exception as e:
AuthenticationService.set_user_has_logged_out()
raise ApiError(
error_code="fail_get_user_info",
message="Cannot get user info from token",
@ -396,6 +398,7 @@ def _get_user_model_from_token(token: str) -> UserModel | None:
.first()
)
if user_model is None:
AuthenticationService.set_user_has_logged_out()
raise ApiError(
error_code="invalid_user",
message="Invalid user. Please log in.",
@ -403,6 +406,7 @@ def _get_user_model_from_token(token: str) -> UserModel | None:
)
# no user_info
else:
AuthenticationService.set_user_has_logged_out()
raise ApiError(
error_code="no_user_info",
message="Cannot retrieve user info",
@ -411,6 +415,7 @@ def _get_user_model_from_token(token: str) -> UserModel | None:
else:
current_app.logger.debug("token_type not in decode_token in verify_token")
AuthenticationService.set_user_has_logged_out()
raise ApiError(
error_code="invalid_token",
message="Invalid token. Please log in.",

View File

@ -230,6 +230,7 @@ class AuthenticationService:
valid = False
if valid and now > decoded_token["exp"]:
AuthenticationService.set_user_has_logged_out()
raise TokenExpiredError("Your token is expired. Please Login")
elif not valid:
current_app.logger.error(
@ -353,3 +354,8 @@ class AuthenticationService:
tld.new_access_token = g.token
tld.new_id_token = g.token
tld.new_authentication_identifier = authentication_identifier
@classmethod
def set_user_has_logged_out(cls) -> None:
tld = current_app.config["THREAD_LOCAL_DATA"]
tld.user_has_logged_out = True

View File

@ -1,12 +1,13 @@
import { ArrowRight } from '@carbon/icons-react';
import { useEffect, useState } from 'react';
import { Loading, Button, Grid, Column } from '@carbon/react';
import { useSearchParams } from 'react-router-dom';
import { useNavigate, useSearchParams } from 'react-router-dom';
import { AuthenticationOption } from '../interfaces';
import HttpService from '../services/HttpService';
import UserService from '../services/UserService';
export default function Login() {
const navigate = useNavigate();
const [searchParams] = useSearchParams();
const [authenticationOptions, setAuthenticationOptions] = useState<
AuthenticationOption[] | null
@ -18,6 +19,14 @@ export default function Login() {
});
}, []);
const getOriginalUrl = () => {
const originalUrl = searchParams.get('original_url');
if (originalUrl === '/login') {
return '/';
}
return originalUrl;
};
const authenticationOptionButtons = () => {
if (!authenticationOptions) {
return null;
@ -30,9 +39,7 @@ export default function Login() {
size="lg"
className="login-button"
renderIcon={ArrowRight}
onClick={() =>
UserService.doLogin(option, searchParams.get('original_url'))
}
onClick={() => UserService.doLogin(option, getOriginalUrl())}
>
{option.label}
</Button>
@ -46,10 +53,7 @@ export default function Login() {
return;
}
if (authenticationOptions.length === 1) {
UserService.doLogin(
authenticationOptions[0],
searchParams.get('original_url')
);
UserService.doLogin(authenticationOptions[0], getOriginalUrl());
}
};
@ -89,6 +93,11 @@ export default function Login() {
);
};
if (UserService.isLoggedIn()) {
navigate('/');
return null;
}
if (authenticationOptions === null || authenticationOptions.length < 2) {
doLoginIfAppropriate();
return (

View File

@ -75,6 +75,8 @@ backendCallProps) => {
const updatedPath = path.replace(/^\/v1\.0/, '');
let isSuccessful = true;
// this fancy 403 handling is like this because we want to get the response body.
// otherwise, we would just throw an exception.
let is403 = false;
fetch(`${BACKEND_BASE_URL}${updatedPath}`, httpArgs)
.then((response) => {
@ -120,6 +122,11 @@ backendCallProps) => {
} else {
console.error(error.message);
}
} else if (
!UserService.isLoggedIn() &&
window.location.pathname !== '/login'
) {
window.location.href = `/login?original_url=${UserService.getCurrentLocation()}`;
}
});
};