@@ -26,6 +26,7 @@ import { Tooltip } from "@heroui/tooltip";
2626import { FC } from "react" ;
2727import { useTranslation } from "react-i18next" ;
2828import { Link } from "@heroui/link" ;
29+ import { createRemoteJWKSet , JWTPayload , jwtVerify } from "jose" ;
2930
3031import { SiteLoading } from "./site-loading" ;
3132
@@ -292,7 +293,10 @@ export const LoginLogoutLink: FC<LogoutLinkProps> = ({
292293 * <AuthenticationGuard component={ProtectedDashboard} />
293294 * ```
294295 */
295- export const AuthenticationGuard : FC < { component : FC } > = ( { component } ) => {
296+ export const AuthenticationGuard : FC < {
297+ component : FC ;
298+ permission ?: string ;
299+ } > = ( { component } ) => {
296300 const Component = withAuthenticationRequired ( component , {
297301 onRedirecting : ( ) => (
298302 < >
@@ -349,3 +353,47 @@ export const getJsonFromSecuredApi = async (
349353 throw error ;
350354 }
351355} ;
356+
357+ /**
358+ * Checks if the user has a specific permission.
359+ * @param permission - The permission to check for
360+ * @param {GetAccessTokenFunction } getAccessTokenFunction - Function to retrieve an access token, typically Auth0's getAccessTokenSilently
361+ * @returns {Promise<boolean> } Promise resolving to true if the user has the permission, false otherwise
362+ * @throws {Error } If token acquisition fails or the API request fails
363+ */
364+ export const userHasPermission = async (
365+ permission : string ,
366+ getAccessTokenFunction : GetAccessTokenFunction ,
367+ ) => {
368+ try {
369+ const accessToken = await getAccessTokenFunction ( {
370+ authorizationParams : {
371+ audience : import . meta. env . AUTH0_AUDIENCE ,
372+ scope : import . meta. env . AUTH0_SCOPE ,
373+ } ,
374+ } ) ;
375+
376+ if ( ! accessToken ) {
377+ return false ;
378+ }
379+ const JWKS = createRemoteJWKSet (
380+ new URL ( `https://${ import . meta. env . AUTH0_DOMAIN } /.well-known/jwks.json` ) ,
381+ ) ;
382+
383+ const joseResult = await jwtVerify ( accessToken , JWKS , {
384+ issuer : `https://${ import . meta. env . AUTH0_DOMAIN } /` ,
385+ audience : import . meta. env . AUTH0_AUDIENCE ,
386+ } ) ;
387+ const payload = joseResult . payload as JWTPayload ;
388+
389+ if ( payload . permissions instanceof Array ) {
390+ return payload . permissions . includes ( permission ) ;
391+ } else {
392+ return false ;
393+ }
394+ } catch ( error ) {
395+ // eslint-disable-next-line no-console
396+ console . error ( error ) ;
397+ throw error ;
398+ }
399+ } ;
0 commit comments