From e626c8f0880e474f7ca220aff15ad0d6ce106337 Mon Sep 17 00:00:00 2001 From: Ann Catton Date: Wed, 17 Feb 2021 17:12:13 -0500 Subject: [PATCH 1/3] Remove incorrect import. Temporary typing until using updated ego-token-utils --- components/UserDropdown.tsx | 17 ++++++++++++++++- global/hooks/useAuthContext.tsx | 18 +++++++++++------- global/types.ts | 11 ++++++++--- global/utils/egoTokenUtils.ts | 9 ++++++--- 4 files changed, 41 insertions(+), 14 deletions(-) diff --git a/components/UserDropdown.tsx b/components/UserDropdown.tsx index a42bdd93..9acf44f5 100644 --- a/components/UserDropdown.tsx +++ b/components/UserDropdown.tsx @@ -6,6 +6,21 @@ import { useTheme } from 'emotion-theming'; import defaultTheme from './theme'; import { Avatar, ChevronDown } from './theme/icons'; import useAuthContext from '../global/hooks/useAuthContext'; +import { UserWithId } from '../global/types'; + +const getDisplayName = (user?: UserWithId) => { + const greeting = 'Hello'; + if (user) { + if (user.firstName) { + return `${greeting}, ${user.firstName}`; + } else if (user.lastName) { + return `${greeting}, ${user.lastName}`; + } else if (user.email) { + return `${greeting}, ${user.email}`; + } + } + return greeting; +}; const CurrentUser = () => { const { user } = useAuthContext(); @@ -30,7 +45,7 @@ const CurrentUser = () => { max-width: 142px; `} > - Hello, {user?.firstName} + {getDisplayName(user)} ); diff --git a/global/hooks/useAuthContext.tsx b/global/hooks/useAuthContext.tsx index 00009936..ffc784ac 100644 --- a/global/hooks/useAuthContext.tsx +++ b/global/hooks/useAuthContext.tsx @@ -2,13 +2,13 @@ import React, { createContext, useState } from 'react'; import { useRouter } from 'next/router'; import { EGO_JWT_KEY } from '../utils/constants'; -import { decodeToken, extractUser, getPermissionsFromToken } from '../utils/egoTokenUtils'; -import { UserWithId } from '../../global/types'; +import { decodeToken, extractUser, isValidJwt } from '../utils/egoTokenUtils'; +import { UserWithId, UserWithProviderInfo } from '../../global/types'; type T_AuthContext = { token?: string; logout: () => void; - user?: UserWithId; + user?: any; // will be corrected when new ego-token-utils User type is available fetchWithAuth: typeof fetch; }; @@ -42,13 +42,17 @@ export const AuthProvider = ({ }; if (token !== egoJwt) { - setTokenState(egoJwt); + if (isValidJwt(egoJwt)) { + setTokenState(egoJwt); + } else { + setTokenState(null); + } } - const fetchWithAuth = (url: string, options: any) => { + const fetchWithAuth: T_AuthContext['fetchWithAuth'] = (url, options) => { return fetch(url, { ...options, - headers: { ...options.headers, accept: '*/*', Authorization: `Bearer ${token || ''}` }, + headers: { ...options?.headers, accept: '*/*', Authorization: `Bearer ${token || ''}` }, body: null, }); }; @@ -56,7 +60,7 @@ export const AuthProvider = ({ const userInfo = token ? decodeToken(token) : null; // ts error on userInfo from type discrepancy between dms and ego-token-utils user.preferredLanguage // dms will need to use token-utils version updated for ego 4.x.x - const user = userInfo ? extractUser(userInfo) : {}; + const user = userInfo ? extractUser(userInfo) : undefined; const authData = { token, logout, diff --git a/global/types.ts b/global/types.ts index 10631393..b37738c7 100644 --- a/global/types.ts +++ b/global/types.ts @@ -32,11 +32,11 @@ export interface User { lastName: string; createdAt: number; lastLogin: number; - preferredLanguage?: Language; - providerType: ProviderType; - providerSubjectId: string; + preferredLanguage?: string; } +// will update User to include providerSubjectId and providerType once new version of ego-token-utils for Ego 4.x.x is available +// preferredLanguage can be updated to enum export type EgoJwtData = { iat: number; exp: number; @@ -53,3 +53,8 @@ export type EgoJwtData = { export interface UserWithId extends User { id: string; } + +export interface UserWithProviderInfo extends UserWithId { + providerType: ProviderType; + providerSubjectId: string; +} diff --git a/global/utils/egoTokenUtils.ts b/global/utils/egoTokenUtils.ts index e77c91f8..3467d456 100644 --- a/global/utils/egoTokenUtils.ts +++ b/global/utils/egoTokenUtils.ts @@ -9,12 +9,15 @@ const TokenUtils = createEgoUtils(getConfig().NEXT_PUBLIC_EGO_PUBLIC_KEY); export const isValidJwt = (egoJwt: string | undefined) => !!egoJwt && TokenUtils.isValidJwt(egoJwt); export const decodeToken = memoize((egoJwt?: string) => - egoJwt ? TokenUtils.decodeToken(egoJwt) : null, + egoJwt && isValidJwt(egoJwt) ? TokenUtils.decodeToken(egoJwt) : null, ); -export const extractUser: (decodedToken: EgoJwtData) => UserWithId | {} = (decodedToken) => { +// EgoJwtData will need to be updated in ego-token-utils to include new User type in Ego 4.x.x +// that includes providerSubjectId and providerType, and removes name +// matching older version for now +export const extractUser = (decodedToken: EgoJwtData) => { if (decodedToken) { return { ...decodedToken?.context.user, id: decodedToken?.sub }; } - return {}; + return undefined; }; From 1ca5099cc260a98707388de1ad2c661109a4f3a0 Mon Sep 17 00:00:00 2001 From: Ann Catton Date: Fri, 19 Feb 2021 18:17:35 -0500 Subject: [PATCH 2/3] replace ego token utils. fix typing issues --- global/hooks/useAuthContext.tsx | 16 +++++++--------- global/types.ts | 9 ++------- global/utils/egoTokenUtils.ts | 30 +++++++++++++++++++++--------- next-env.d.ts | 1 + package-lock.json | 13 +++++-------- package.json | 3 ++- 6 files changed, 38 insertions(+), 34 deletions(-) diff --git a/global/hooks/useAuthContext.tsx b/global/hooks/useAuthContext.tsx index ffc784ac..5a9ff755 100644 --- a/global/hooks/useAuthContext.tsx +++ b/global/hooks/useAuthContext.tsx @@ -3,12 +3,12 @@ import { useRouter } from 'next/router'; import { EGO_JWT_KEY } from '../utils/constants'; import { decodeToken, extractUser, isValidJwt } from '../utils/egoTokenUtils'; -import { UserWithId, UserWithProviderInfo } from '../../global/types'; +import { UserWithId } from '../../global/types'; type T_AuthContext = { token?: string; logout: () => void; - user?: any; // will be corrected when new ego-token-utils User type is available + user?: UserWithId; fetchWithAuth: typeof fetch; }; @@ -42,11 +42,11 @@ export const AuthProvider = ({ }; if (token !== egoJwt) { - if (isValidJwt(egoJwt)) { - setTokenState(egoJwt); - } else { - setTokenState(null); - } + setTokenState(egoJwt); + } + + if (token && !isValidJwt(token)) { + logout(); } const fetchWithAuth: T_AuthContext['fetchWithAuth'] = (url, options) => { @@ -58,8 +58,6 @@ export const AuthProvider = ({ }; const userInfo = token ? decodeToken(token) : null; - // ts error on userInfo from type discrepancy between dms and ego-token-utils user.preferredLanguage - // dms will need to use token-utils version updated for ego 4.x.x const user = userInfo ? extractUser(userInfo) : undefined; const authData = { token, diff --git a/global/types.ts b/global/types.ts index b37738c7..79b4b124 100644 --- a/global/types.ts +++ b/global/types.ts @@ -33,10 +33,10 @@ export interface User { createdAt: number; lastLogin: number; preferredLanguage?: string; + providerType: ProviderType; + providerSubjectId: string; } -// will update User to include providerSubjectId and providerType once new version of ego-token-utils for Ego 4.x.x is available -// preferredLanguage can be updated to enum export type EgoJwtData = { iat: number; exp: number; @@ -53,8 +53,3 @@ export type EgoJwtData = { export interface UserWithId extends User { id: string; } - -export interface UserWithProviderInfo extends UserWithId { - providerType: ProviderType; - providerSubjectId: string; -} diff --git a/global/utils/egoTokenUtils.ts b/global/utils/egoTokenUtils.ts index 3467d456..fa21c756 100644 --- a/global/utils/egoTokenUtils.ts +++ b/global/utils/egoTokenUtils.ts @@ -1,21 +1,33 @@ -import createEgoUtils from '@icgc-argo/ego-token-utils'; +import jwtDecode from 'jwt-decode'; import { memoize } from 'lodash'; +import jwt from 'jsonwebtoken'; import { getConfig } from '../config'; import { EgoJwtData, UserWithId } from '../types'; -const TokenUtils = createEgoUtils(getConfig().NEXT_PUBLIC_EGO_PUBLIC_KEY); +const { NEXT_PUBLIC_EGO_PUBLIC_KEY } = getConfig(); -export const isValidJwt = (egoJwt: string | undefined) => !!egoJwt && TokenUtils.isValidJwt(egoJwt); +const verifyJwt: (egoPublicKey: string) => (egoJwt?: string) => boolean = (egoPublicKey) => ( + egoJwt, +) => { + try { + if (!egoJwt || !egoPublicKey) { + return false; + } else { + return jwt.verify(egoJwt, egoPublicKey, { algorithms: ['RS256'] }) && true; + } + } catch (err) { + return false; + } +}; + +export const isValidJwt = verifyJwt(NEXT_PUBLIC_EGO_PUBLIC_KEY); -export const decodeToken = memoize((egoJwt?: string) => - egoJwt && isValidJwt(egoJwt) ? TokenUtils.decodeToken(egoJwt) : null, +export const decodeToken: (egoJwt?: string) => EgoJwtData | null = memoize((egoJwt) => + egoJwt && isValidJwt(egoJwt) ? jwtDecode(egoJwt) : null, ); -// EgoJwtData will need to be updated in ego-token-utils to include new User type in Ego 4.x.x -// that includes providerSubjectId and providerType, and removes name -// matching older version for now -export const extractUser = (decodedToken: EgoJwtData) => { +export const extractUser: (decodedToken: EgoJwtData) => UserWithId | undefined = (decodedToken) => { if (decodedToken) { return { ...decodedToken?.context.user, id: decodedToken?.sub }; } diff --git a/next-env.d.ts b/next-env.d.ts index 96f65894..c6c4e86f 100644 --- a/next-env.d.ts +++ b/next-env.d.ts @@ -3,3 +3,4 @@ declare module 'url-join'; declare module 'js-cookie'; +declare module 'jsonwebtoken'; diff --git a/package-lock.json b/package-lock.json index 62a9e5ad..36500d34 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1708,14 +1708,6 @@ "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.1.1.tgz", "integrity": "sha512-CAEbWH7OIur6jEOzaai83jq3FmKmv4PmX1JYfs9IrYcGEVI/lyL1EXJGCj7eFVJ0bg5QR8LMxBlEtA+xKiLpFw==" }, - "@icgc-argo/ego-token-utils": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@icgc-argo/ego-token-utils/-/ego-token-utils-8.0.0.tgz", - "integrity": "sha512-sgBHslKS3TnSSCNcdOpwrophLRrZitVpnussv4iRD0VKn6OFCfR32AXn+Ri9LF6KifS3FsE1WtvAYNJx1Ewz7g==", - "requires": { - "jsonwebtoken": "^8.5.1" - } - }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -8421,6 +8413,11 @@ "safe-buffer": "^5.0.1" } }, + "jwt-decode": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", + "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", diff --git a/package.json b/package.json index 70b59ac7..5aec78ef 100644 --- a/package.json +++ b/package.json @@ -13,11 +13,12 @@ "@emotion/babel-preset-css-prop": "^10.0.27", "@emotion/core": "^10.0.35", "@emotion/styled": "^10.0.27", - "@icgc-argo/ego-token-utils": "^8.0.0", "@types/lodash": "^4.14.168", "@zeit/next-css": "^1.0.1", "axios": "^0.21.1", "emotion-theming": "^10.0.27", + "jsonwebtoken": "^8.5.1", + "jwt-decode": "^3.1.2", "lodash": "^4.17.20", "next": "^9.5.4", "query-string": "^6.13.8", From 44e0efe459d31efd33f8ad1ca2b6d7496287a0c4 Mon Sep 17 00:00:00 2001 From: Ann Catton Date: Fri, 19 Feb 2021 18:21:49 -0500 Subject: [PATCH 3/3] fix type --- global/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global/types.ts b/global/types.ts index 79b4b124..10631393 100644 --- a/global/types.ts +++ b/global/types.ts @@ -32,7 +32,7 @@ export interface User { lastName: string; createdAt: number; lastLogin: number; - preferredLanguage?: string; + preferredLanguage?: Language; providerType: ProviderType; providerSubjectId: string; }