Skip to content

Commit

Permalink
🐛 Fixed Expired JWT Token By Refreshing it (#1353)
Browse files Browse the repository at this point in the history
* enable refresh token for Reactions

* make refreshIdToken reusable (hook)

* use refreshed id token for all apis

* fix order

* log in again in case the refresh token is expired

* move auth0_scope to .env
  • Loading branch information
Aibono1225 committed May 28, 2024
1 parent aefdeb8 commit fbbbaa3
Show file tree
Hide file tree
Showing 11 changed files with 88 additions and 34 deletions.
1 change: 1 addition & 0 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ API_BASE_URL=#{API_BASE_URL}
AUTH0_DOMAIN=#{AUTH0_DOMAIN}
AUTH0_CLIENT_ID=#{AUTH0_CLIENT_ID}
AUTH0_REDIRECT_URI=#{AUTH0_REDIRECT_URI}
AUTH0_SCOPE=#{AUTH0_SCOPE}
GITHUB_API_PAT=#{GITHUB_API_PAT}
DISQUS_FORUM=#{DISQUS_FORUM}
DISQUS_API_KEY=#{DISQUS_API_KEY}
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/template-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ jobs:
AUTH0_DOMAIN: ${{ vars.AUTH0_DOMAIN }}
AUTH0_CLIENT_ID: ${{ vars.AUTH0_CLIENT_ID }}
AUTH0_REDIRECT_URI: ${{ vars.AUTH0_REDIRECT_URI }}
AUTH0_SCOPE: ${{ vars.AUTH0_SCOPE }}
GITHUB_API_PAT: ${{ secrets.CONTENT_GITHUB_TOKEN }}
DISQUS_FORUM: ${{ vars.DISQUS_FORUM }}
DISQUS_API_KEY: ${{ secrets.DISQUS_API_KEY }}
Expand Down
11 changes: 6 additions & 5 deletions src/components/bookmark/bookmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
BookmarkRule,
RemoveBookmark,
} from '../../services/apiService';
import { useAuthService } from '../../services/authService';
import PropTypes from 'prop-types';
import { ApplicationInsights } from '@microsoft/applicationinsights-web';

Expand All @@ -21,8 +22,8 @@ const Bookmark = (props) => {
const [change, setChange] = useState(0);
const [bookmarked, setBookmarked] = useState(false);

const { isAuthenticated, user, getIdTokenClaims, loginWithRedirect } =
useAuth0();
const { isAuthenticated, user, loginWithRedirect } = useAuth0();
const { fetchIdToken } = useAuthService();

useEffect(() => {
if (isAuthenticated) {
Expand All @@ -42,10 +43,10 @@ const Bookmark = (props) => {
async function onClick() {
if (isAuthenticated) {
setBookmarked(!bookmarked);
const jwt = await getIdTokenClaims();
const jwt = await fetchIdToken();
const data = { ruleGuid: ruleId, UserId: user.sub };
!bookmarked
? BookmarkRule(data, jwt.__raw)
? BookmarkRule(data, jwt)
.then(() => {
setChange(change + 1);
})
Expand All @@ -55,7 +56,7 @@ const Bookmark = (props) => {
severityLevel: 3,
});
})
: RemoveBookmark({ ruleGuid: ruleId, UserId: user.sub }, jwt.__raw)
: RemoveBookmark({ ruleGuid: ruleId, UserId: user.sub }, jwt)
.then(() => {
setChange(change + 1);
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
ConnectUserCommentsAccount,
DisqusError,
} from '../../services/apiService';
import { useAuthService } from '../../services/authService';
import DisqusIcon from '-!svg-react-loader!../../images/disqusIcon.svg';

import { useAuth0 } from '@auth0/auth0-react';
Expand All @@ -20,7 +21,8 @@ const CommentsNotConnected = ({ userCommentsConnected, setState, state }) => {
const [disqusUsername, setDisqusUsername] = useState();
const [errorMessage, setErrorMessage] = useState(null);

const { user, getIdTokenClaims } = useAuth0();
const { user } = useAuth0();
const { fetchIdToken } = useAuthService();

function connectAccounts() {
if (disqusUsername) {
Expand All @@ -29,13 +31,13 @@ const CommentsNotConnected = ({ userCommentsConnected, setState, state }) => {
if (success.code == DisqusError.InvalidArg) {
setErrorMessage('Username does not exist');
}
const jwt = await getIdTokenClaims();
const jwt = await fetchIdToken();
ConnectUserCommentsAccount(
{
UserId: user.sub,
CommentsUserId: success.response.id,
},
jwt.__raw
jwt
)
.then((response) => {
setState(state + 1);
Expand Down
3 changes: 2 additions & 1 deletion src/components/layout/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,11 @@ const Layout = ({
authorizationParams={{
redirect_uri: process.env.AUTH0_REDIRECT_URI,
}}
// redirectUri={process.env.AUTH0_REDIRECT_URI}
onRedirectCallback={onRedirectCallback}
useRefreshTokens={true}
cacheLocation="localstorage"
scope={process.env.AUTH0_SCOPE}
audience={process.env.AUTH0_DOMAIN}
>
{/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */}
<div
Expand Down
21 changes: 12 additions & 9 deletions src/components/profile-content/profile-content.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
GetUser,
DisqusError,
} from '../../services/apiService';
import { useAuthService } from '../../services/authService';
import BookmarkIcon from '-!svg-react-loader!../../images/bookmarkIcon.svg';
import DisqusIcon from '-!svg-react-loader!../../images/disqusIcon.svg';

Expand Down Expand Up @@ -50,20 +51,21 @@ const ProfileContent = (props) => {
const [disqusPrivacyEnabled, setDisqusPrivacyEnabled] = useState(false);
const [change, setChange] = useState(0);
const [viewStyle, setViewStyle] = useState('titleOnly');
const { user, getIdTokenClaims, isAuthenticated } = useAuth0();
const { user, isAuthenticated } = useAuth0();
const { fetchIdToken } = useAuthService();

const handleOptionChange = (e) => {
setViewStyle(e.target.value);
};

async function onRemoveClick(ruleGuid) {
const jwt = await getIdTokenClaims();
const jwt = await fetchIdToken();
if (
isAuthenticated &&
window.confirm('Are you sure you want to remove this tag?')
) {
props.filter == Filter.Bookmarks
? RemoveBookmark({ ruleGuid: ruleGuid, UserId: user.sub }, jwt.__raw)
? RemoveBookmark({ ruleGuid: ruleGuid, UserId: user.sub }, jwt)
.then(() => {
setChange(change + 1);
props.setState(props.state + 1);
Expand All @@ -74,7 +76,7 @@ const ProfileContent = (props) => {
severityLevel: 3,
});
})
: RemoveReaction({ ruleGuid: ruleGuid, UserId: user.sub }, jwt.__raw)
: RemoveReaction({ ruleGuid: ruleGuid, UserId: user.sub }, jwt)
.then(() => {
setChange(change + 1);
})
Expand Down Expand Up @@ -139,8 +141,8 @@ const ProfileContent = (props) => {
}

async function getUserComments() {
const jwt = await getIdTokenClaims();
GetUser(user.sub, jwt.__raw).then((success) => {
const jwt = await fetchIdToken();
GetUser(user.sub, jwt).then((success) => {
if (!success) {
appInsights.trackException({
error: new Error('Error getting user'),
Expand Down Expand Up @@ -350,11 +352,12 @@ const RuleList = ({
const components = {
greyBox: GreyBox,
};
const { user, getIdTokenClaims } = useAuth0();
const { user } = useAuth0();
const { fetchIdToken } = useAuthService();

async function RemoveDisqusUser() {
const jwt = await getIdTokenClaims();
RemoveUserCommentsAccount({ UserId: user.sub }, jwt.__raw)
const jwt = await fetchIdToken();
RemoveUserCommentsAccount({ UserId: user.sub }, jwt)
.then(() => {
setState(state + 1);
})
Expand Down
11 changes: 6 additions & 5 deletions src/components/reaction/reaction.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
ReactionType,
RemoveReaction,
} from '../../services/apiService';
import { useAuthService } from '../../services/authService';
import { ApplicationInsights } from '@microsoft/applicationinsights-web';

const appInsights = new ApplicationInsights({
Expand All @@ -25,8 +26,8 @@ const Reaction = (props) => {
const [change, setChange] = useState(0);
const [currentReactionType, setCurrentReactionType] = useState(null);

const { isAuthenticated, user, getIdTokenClaims, loginWithRedirect } =
useAuth0();
const { isAuthenticated, user, loginWithRedirect } = useAuth0();
const { fetchIdToken } = useAuthService();

useEffect(() => {
if (isAuthenticated) {
Expand Down Expand Up @@ -81,11 +82,11 @@ const Reaction = (props) => {
ruleGuid: ruleId,
userId: user.sub,
};
const jwt = await getIdTokenClaims();
const idToken = await fetchIdToken();
if (currentReactionType == type) {
removePreviousReaction();
setCurrentReactionType(null);
RemoveReaction(data, jwt.__raw)
RemoveReaction(data, idToken)
.then(() => {
setChange(change + 1);
})
Expand All @@ -109,7 +110,7 @@ const Reaction = (props) => {
removePreviousReaction();
}
setCurrentReactionType(type);
PostReactionForUser(data, jwt.__raw)
PostReactionForUser(data, idToken)
.then(() => {
setChange(change + 1);
})
Expand Down
9 changes: 5 additions & 4 deletions src/components/signin/signin.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
GetGithubOrganisations,
setUserOrganisation,
} from '../../services/apiService';
import { useAuthService } from '../../services/authService';
import { ApplicationInsights } from '@microsoft/applicationinsights-web';

const appInsights = new ApplicationInsights({
Expand All @@ -15,8 +16,8 @@ const appInsights = new ApplicationInsights({
});

const SignIn = () => {
const { isAuthenticated, loginWithRedirect, user, getIdTokenClaims } =
useAuth0();
const { isAuthenticated, loginWithRedirect, user } = useAuth0();
const { fetchIdToken } = useAuthService();

useEffect(() => {
isAuthenticated ? setUserOrg() : null;
Expand All @@ -26,13 +27,13 @@ const SignIn = () => {
isAuthenticated
? await GetGithubOrganisations(user.nickname)
.then(async (success) => {
const jwt = await getIdTokenClaims();
const jwt = await fetchIdToken();
success.forEach(async (org) => {
const data = {
OrganisationId: org.id.toString(),
UserId: user.sub,
};
await setUserOrganisation(data, jwt.__raw).catch((err) => {
await setUserOrganisation(data, jwt).catch((err) => {
console.error('error: ' + err);
});
});
Expand Down
9 changes: 5 additions & 4 deletions src/pages/profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import GitHubIcon from '-!svg-react-loader!../images/github.svg';
import DisqusIcon from '-!svg-react-loader!../images/disqusIcon.svg';
import { useAuth0 } from '@auth0/auth0-react';
import { GetUser } from '../services/apiService';
import { useAuthService } from '../services/authService';
import { ApplicationInsights } from '@microsoft/applicationinsights-web';

const appInsights = new ApplicationInsights({
Expand All @@ -21,8 +22,8 @@ const appInsights = new ApplicationInsights({
const Profile = ({ data, gitHubUsername }) => {
const [selectedFilter, setSelectedFilter] = useState(4);
const [state, setState] = useState(0);
const { user, isAuthenticated, loginWithRedirect, getIdTokenClaims } =
useAuth0();
const { user, isAuthenticated, loginWithRedirect } = useAuth0();
const { fetchIdToken } = useAuthService();
const [commentsConnected, setCommentsConnected] = useState(false);
const [bookmarkedRulesCount, setBookmarkedRulesCount] = useState();
const [superLikedRulesCount, setSuperLikedRulesCount] = useState();
Expand All @@ -32,8 +33,8 @@ const Profile = ({ data, gitHubUsername }) => {
const [commentedRulesCount, setCommentedRulesCount] = useState();

async function CheckUser() {
const jwt = await getIdTokenClaims();
GetUser(user.sub, jwt.__raw)
const jwt = await fetchIdToken();
GetUser(user.sub, jwt)
.then((success) => {
setCommentsConnected(success.commentsConnected);
})
Expand Down
40 changes: 40 additions & 0 deletions src/services/authService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { useAuth0 } from '@auth0/auth0-react';

export const useAuthService = () => {
const { getIdTokenClaims, getAccessTokenSilently, loginWithRedirect } =
useAuth0();

const fetchIdToken = async () => {
try {
const claims = await getIdTokenClaims();
const expiryTime = claims.exp * 1000;
const currentTime = new Date().getTime();

if (expiryTime - currentTime < 60000) {
await getAccessTokenSilently({
audience: process.env.AUTH0_DOMAIN,
scope: process.env.AUTH0_SCOPE,
cacheMode: 'off',
});

const refreshedClaims = await getIdTokenClaims();
return refreshedClaims.__raw;
}
return claims.__raw;
} catch (error) {
if (window.confirm('Your session has expired. Please log in again')) {
const currentPage =
typeof window !== 'undefined'
? window.location.pathname.split('/').pop()
: null;
await loginWithRedirect({
appState: {
targetUrl: currentPage,
},
});
}
}
};

return { fetchIdToken };
};
8 changes: 5 additions & 3 deletions src/templates/rule.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import RuleSideBar from '../components/rule-side-bar/rule-side-bar';
import formatDistance from 'date-fns/formatDistance';
import { format } from 'date-fns';
import { useAuth0 } from '@auth0/auth0-react';
import { useAuthService } from '../services/authService';
import { faGithub } from '@fortawesome/free-brands-svg-icons';

const appInsights = new ApplicationInsights({
Expand All @@ -41,20 +42,21 @@ const Rule = ({ data, location }) => {
};
const rule = data.markdownRemark;
const categories = data.categories.nodes;
const { user, isAuthenticated, getIdTokenClaims } = useAuth0();
const { user, isAuthenticated } = useAuth0();
const { fetchIdToken } = useAuthService();
const [hiddenCount, setHiddenCount] = useState(0);

const loadSecretContent = async (userOrgId) => {
const hidden = document.getElementsByClassName('hidden');
if (hidden.length != 0) {
const token = await getIdTokenClaims();
const token = await fetchIdToken();
for (var hiddenBlock of hidden) {
const contentID = hiddenBlock.textContent || hiddenBlock.innerText;
const guid = contentID.substring(0, 36);
const orgID = contentID.substring(37);
if (parseInt(orgID) == parseInt(userOrgId)) {
isAuthenticated && guid
? await GetSecretContent(guid, token.__raw)
? await GetSecretContent(guid, token)
.then((success) => {
GetGithubOrganisationName(orgID)
.then((nameSuccess) => {
Expand Down

0 comments on commit fbbbaa3

Please sign in to comment.