From a9617e6e01df3c5616a118455e86947e9deef500 Mon Sep 17 00:00:00 2001 From: Dimitris Karagiannis Date: Sat, 11 Nov 2023 05:02:34 +0200 Subject: [PATCH] feat: add permissions to Auth provider values, add a few more deps in Toolbox effect's deps array --- .../docs/api/Types/GetAccessTokenSilently.mdx | 17 ++++++++++++++ documentation/docs/api/Types/Permissions.mdx | 17 ++++++++++++++ .../_type-definitions/DecodedTokenResponse.md | 23 +++++++++---------- .../GetAccessTokenSilently.md | 1 + .../docs/api/_type-definitions/Permissions.md | 1 + .../UseAuthenticationReturnValue.md | 17 +++++++------- .../UseOrfiumProductsReturnValue.md | 2 +- .../UseOrganizationsReturnValue.md | 10 ++++---- src/contexts/authentication.ts | 16 +++++++++---- src/contexts/index.ts | 7 +++++- src/providers/Authentication.tsx | 15 +++++++++--- 11 files changed, 91 insertions(+), 35 deletions(-) create mode 100644 documentation/docs/api/Types/GetAccessTokenSilently.mdx create mode 100644 documentation/docs/api/Types/Permissions.mdx create mode 100644 documentation/docs/api/_type-definitions/GetAccessTokenSilently.md create mode 100644 documentation/docs/api/_type-definitions/Permissions.md diff --git a/documentation/docs/api/Types/GetAccessTokenSilently.mdx b/documentation/docs/api/Types/GetAccessTokenSilently.mdx new file mode 100644 index 00000000..b66f1e6b --- /dev/null +++ b/documentation/docs/api/Types/GetAccessTokenSilently.mdx @@ -0,0 +1,17 @@ +--- +id: 'GetAccessTokenSilently' +title: 'GetAccessTokenSilently' +sidebar_label: 'GetAccessTokenSilently' +sidebar_position: 1 +--- +import Type from '../_type-definitions/GetAccessTokenSilently.md'; + + +```ts +import { type GetAccessTokenSilently } from '@orfium/toolbox'; +``` + +### Definition + + + diff --git a/documentation/docs/api/Types/Permissions.mdx b/documentation/docs/api/Types/Permissions.mdx new file mode 100644 index 00000000..4156ca1b --- /dev/null +++ b/documentation/docs/api/Types/Permissions.mdx @@ -0,0 +1,17 @@ +--- +id: 'Permissions' +title: 'Permissions' +sidebar_label: 'Permissions' +sidebar_position: 1 +--- +import Type from '../_type-definitions/Permissions.md'; + + +```ts +import { type Permissions } from '@orfium/toolbox'; +``` + +### Definition + + + diff --git a/documentation/docs/api/_type-definitions/DecodedTokenResponse.md b/documentation/docs/api/_type-definitions/DecodedTokenResponse.md index 150db1e5..cab2201c 100644 --- a/documentation/docs/api/_type-definitions/DecodedTokenResponse.md +++ b/documentation/docs/api/_type-definitions/DecodedTokenResponse.md @@ -1,12 +1,11 @@ -| Name | Type | -| :------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `iss?` | `string` | -| `sub?` | `string` | -| `aud?` | `string[]` | -| `iat?` | `number` | -| `exp?` | `number` | -| `azp?` | `string` | -| `scope?` | `string` | -| `org_id?` | `string` (_the organization id of the user currently selected_) | -| `permissions?` | `string[]` (_the permissions defined on the user for more info visit https://orfium.atlassian.net/wiki/spaces/OPS/pages/2554134739/Roles+and+Permissions#Organization-Roles_) | - +| Name | Type | Info | +| :------------- | :------------------------------------------- |:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `iss?` | `string` | | +| `sub?` | `string` | | +| `aud?` | `string[]` | | +| `iat?` | `number` | | +| `exp?` | `number` | | +| `azp?` | `string` | | +| `scope?` | `string` | | +| `org_id?` | `string` | The organization id of the user currently selected | +| `permissions?` | [`Permissions`](/docs/api/Types/Permissions) | The permissions defined on the user. For more info visit [this page](https://orfium.atlassian.net/wiki/spaces/OPS/pages/2554134739/Roles+and+Permissions#Organization-Roles) | diff --git a/documentation/docs/api/_type-definitions/GetAccessTokenSilently.md b/documentation/docs/api/_type-definitions/GetAccessTokenSilently.md new file mode 100644 index 00000000..9627a0f3 --- /dev/null +++ b/documentation/docs/api/_type-definitions/GetAccessTokenSilently.md @@ -0,0 +1 @@ +
(opts?: GetTokenSilentlyOptions) => Promise\<
void |
\{
decodedToken: [DecodedTokenResponse](/docs/api/Types/DecodedTokenResponse) | Record\;
token: string;
\}
\>
\ No newline at end of file diff --git a/documentation/docs/api/_type-definitions/Permissions.md b/documentation/docs/api/_type-definitions/Permissions.md new file mode 100644 index 00000000..df2c2579 --- /dev/null +++ b/documentation/docs/api/_type-definitions/Permissions.md @@ -0,0 +1 @@ +`string[]` \ No newline at end of file diff --git a/documentation/docs/api/_type-definitions/UseAuthenticationReturnValue.md b/documentation/docs/api/_type-definitions/UseAuthenticationReturnValue.md index e262dd37..0cbab516 100644 --- a/documentation/docs/api/_type-definitions/UseAuthenticationReturnValue.md +++ b/documentation/docs/api/_type-definitions/UseAuthenticationReturnValue.md @@ -1,8 +1,9 @@ -| Name | Type | -| :----------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `isAuthenticated` | `boolean` | -| `isLoading` | `boolean` | -| `user` | [User](/docs/api/Types/User) | undefined | -| `getAccessTokenSilently` |
(opts?: GetTokenSilentlyOptions) => Promise\<
void |
\{
decodedToken: [DecodedTokenResponse](/docs/api/Types/DecodedTokenResponse) | Record\;
token: string;
\}
\>
| -| `loginWithRedirect` | (o?: RedirectLoginOptions\) => Promise\ | -| `logout` | `() => void` | +| Name | Type | +| :----------------------- |:------------------------------------------------------------------| +| `isAuthenticated` | `boolean` | +| `isLoading` | `boolean` | +| `permissions` | [`Permissions`](/docs/api/Types/Permissions) | +| `user` | [User](/docs/api/Types/User) | undefined | +| `getAccessTokenSilently` | [`GetAccessTokenSilently`](/docs/api/Types/GetAccessTokenSilently) | +| `loginWithRedirect` | (o?: RedirectLoginOptions\) => Promise\ | +| `logout` | `() => void` | diff --git a/documentation/docs/api/_type-definitions/UseOrfiumProductsReturnValue.md b/documentation/docs/api/_type-definitions/UseOrfiumProductsReturnValue.md index 3201ba3c..c2d3a958 100644 --- a/documentation/docs/api/_type-definitions/UseOrfiumProductsReturnValue.md +++ b/documentation/docs/api/_type-definitions/UseOrfiumProductsReturnValue.md @@ -1 +1 @@ -[`Product`](../Types/Product)`[] | null` +[Product](/docs/api/Types/Product)[] | null diff --git a/documentation/docs/api/_type-definitions/UseOrganizationsReturnValue.md b/documentation/docs/api/_type-definitions/UseOrganizationsReturnValue.md index ce0ba440..c2be32da 100644 --- a/documentation/docs/api/_type-definitions/UseOrganizationsReturnValue.md +++ b/documentation/docs/api/_type-definitions/UseOrganizationsReturnValue.md @@ -1,5 +1,5 @@ -| Name | Type | -| :--------------------- | :--------------------------------------------------------------- | -| `organizations` | [Organization](../Types/Organization)[] | -| `selectedOrganization` | [Organization](../Types/Organization)[] | null | -| `switchOrganization` | `(organisation: string) => void` | +| Name | Type | +| :--------------------- | :------------------------------------------------------------- | +| `organizations` | [Organization](../Types/Organization)[] | +| `selectedOrganization` | [Organization](../Types/Organization) | null | +| `switchOrganization` | `(organisation: string) => void` | diff --git a/src/contexts/authentication.ts b/src/contexts/authentication.ts index 23270229..f42d281d 100644 --- a/src/contexts/authentication.ts +++ b/src/contexts/authentication.ts @@ -1,6 +1,8 @@ import { type GetTokenSilentlyOptions, type RedirectLoginOptions } from '@auth0/auth0-spa-js'; import { createContext } from 'react'; +export type Permissions = string[]; + export type DecodedTokenResponse = { iss?: string; sub?: string; @@ -12,7 +14,7 @@ export type DecodedTokenResponse = { /** the organization id of the user currently selected **/ org_id?: string; /** the permissions defined on the user for more info visit https://orfium.atlassian.net/wiki/spaces/OPS/pages/2554134739/Roles+and+Permissions#Organization-Roles **/ - permissions?: string[]; + permissions?: Permissions; }; export type User = { @@ -39,16 +41,19 @@ export type User = { [key: string]: any; }; +export type GetAccessTokenSilently = (opts?: GetTokenSilentlyOptions) => Promise<{ + token: string; + decodedToken: DecodedTokenResponse | Record; +} | void>; + export type AuthenticationContextValue = { isAuthenticated: boolean; isLoading: boolean; loginWithRedirect(o?: RedirectLoginOptions): Promise; logout: () => void; - getAccessTokenSilently: (opts?: GetTokenSilentlyOptions) => Promise<{ - token: string; - decodedToken: DecodedTokenResponse | Record; - } | void>; + getAccessTokenSilently: GetAccessTokenSilently; user: User | undefined; + permissions: Permissions; }; export const defaultAuthenticationContextValues: AuthenticationContextValue = { @@ -58,6 +63,7 @@ export const defaultAuthenticationContextValues: AuthenticationContextValue = { loginWithRedirect: () => Promise.resolve(), logout: () => Promise.resolve('logged out'), getAccessTokenSilently: () => Promise.resolve({ token: '', decodedToken: {} }), + permissions: [], }; export const AuthenticationContext = createContext( diff --git a/src/contexts/index.ts b/src/contexts/index.ts index dfecfa9b..ab61885c 100644 --- a/src/contexts/index.ts +++ b/src/contexts/index.ts @@ -1,2 +1,7 @@ -export { type DecodedTokenResponse, type User } from './authentication'; +export { + type DecodedTokenResponse, + type GetAccessTokenSilently, + type Permissions, + type User, +} from './authentication'; export { type Product } from './orfium-products'; diff --git a/src/providers/Authentication.tsx b/src/providers/Authentication.tsx index 451abade..b6d0163a 100644 --- a/src/providers/Authentication.tsx +++ b/src/providers/Authentication.tsx @@ -6,7 +6,11 @@ import { } from '@auth0/auth0-spa-js'; import { useCallback, useEffect, useState, type ReactNode } from 'react'; import { useErrorHandler } from 'react-error-boundary'; -import { AuthenticationContext } from '../contexts/authentication'; +import { + AuthenticationContext, + type GetAccessTokenSilently, + type Permissions, +} from '../contexts/authentication'; import { _useOrganizations } from '../hooks/useOrganizations'; import { getAuth0Client, getTokenSilently, logoutAuth, onRedirectCallback } from '../utils/auth'; @@ -17,6 +21,7 @@ export function Authentication({ children }: AuthenticationProps) { const [user, setUser] = useState>(); const [auth0Client, setAuth0Client] = useState(); const [isLoading, setIsLoading] = useState(true); + const [permissions, setPermissions] = useState([]); // handleError is referentially stable, so it's safe to use as a dep in dep array // https://github.com/bvaughn/react-error-boundary/blob/v3.1.4/src/index.tsx#L165C10-L165C18 @@ -39,7 +44,7 @@ export function Authentication({ children }: AuthenticationProps) { [handleError] ); - const getAccessTokenSilently = useCallback( + const getAccessTokenSilently: GetAccessTokenSilently = useCallback( async (opts?: GetTokenSilentlyOptions) => { try { const result = await getTokenSilently(opts); @@ -84,6 +89,9 @@ export function Authentication({ children }: AuthenticationProps) { if (clientIsAuthenticated) { const clientUser = await client.getUser(); setUser(clientUser); + + const decodedTokenResponse = await getAccessTokenSilently(); + setPermissions(decodedTokenResponse?.decodedToken.permissions || []); } setIsLoading(false); @@ -102,7 +110,7 @@ export function Authentication({ children }: AuthenticationProps) { handleError(error); } })(); - }, [handleError, invitation, loginWithRedirect, organization]); + }, [getAccessTokenSilently, handleError, invitation, loginWithRedirect, organization]); useEffect(() => { if (!isLoading && !isAuthenticated) { @@ -142,6 +150,7 @@ export function Authentication({ children }: AuthenticationProps) { logout: logoutAuth, getAccessTokenSilently: (opts?: GetTokenSilentlyOptions) => getAccessTokenSilently(opts), user, + permissions, }} > {children}