Skip to content

Commit

Permalink
feat: get current tenant (#1040)
Browse files Browse the repository at this point in the history
## Related Issues

Fixes descope/etc#4901

## Description

add `getCurrentTenant` utility
  • Loading branch information
asafshen authored Mar 6, 2025
1 parent 597bd34 commit 76e6f6c
Show file tree
Hide file tree
Showing 14 changed files with 67 additions and 2 deletions.
1 change: 1 addition & 0 deletions packages/sdks/angular-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,7 @@ You can also use the following helper methods on `DescopeAuthService` to assist
- `isRefreshTokenExpired(token = getRefreshToken())` - Check whether the current refresh token is expired. Provide a refresh token if is not persisted.
- `getJwtRoles(token = getSessionToken(), tenant = '')` - Get current roles from an existing session token. Provide tenant id for specific tenant roles.
- `getJwtPermissions(token = getSessionToken(), tenant = '')` - Fet current permissions from an existing session token. Provide tenant id for specific tenant permissions.
- `getCurrentTenant(token = getSessionToken())` - Get current tenant id from an existing session token (from the `dct` claim).

### Refresh token lifecycle

Expand Down
4 changes: 4 additions & 0 deletions packages/sdks/core-js-sdk/src/sdk/helpers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,7 @@ export async function transformResponse<

return ret;
}

export function getCurrentTenant(token: string): string {
return parseJwt(token)?.[DESCOPE_CURRENT_TENANT_CLAIM] || '';
}
12 changes: 12 additions & 0 deletions packages/sdks/core-js-sdk/src/sdk/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
getTenants,
getJwtPermissions,
getJwtRoles,
getCurrentTenant,
isJwtExpired,
transformResponse,
} from './helpers';
Expand Down Expand Up @@ -161,5 +162,16 @@ export default (httpClient: HttpClient) => ({
* @returns The list of roles specified in the given JWT
*/
getJwtRoles: withJwtValidations(getJwtRoles),
/**
* Returns Descope current tenant from the given JWT but DOES NOT check for signature
* @param token A valid token
* @returns The current tenant from the given JWT
*/
getCurrentTenant: withJwtValidations(getCurrentTenant),
/**
* Parses the given JWT token but DOES NOT check for signature
* @param token A valid token
* @returns The parsed JWT token
*/
httpClient,
});
16 changes: 16 additions & 0 deletions packages/sdks/core-js-sdk/test/sdk/sdk.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,22 @@ describe('sdk', () => {
});
});

describe('getCurrentTenant', () => {
it('should throw an error when token is not a string', () => {
expect(sdk.getCurrentTenant).toThrow('"token" must be a string');
});
it('should return the current tenant', () => {
(jwtDecode as jest.Mock).mockImplementation(() => ({
dct: 'current-tenant',
}));
expect(sdk.getCurrentTenant('jwt')).toBe('current-tenant');
});
it('should gracefully handle jwt decoding error', () => {
(jwtDecode as jest.Mock).mockImplementation(() => new Error('error'));
expect(sdk.getCurrentTenant('jwt')).toBeFalsy();
});
});

describe('logout', () => {
it('should throw an error when token is not a string', () => {
expect(() => sdk.logout({ a: 'b' })).toThrow(
Expand Down
1 change: 1 addition & 0 deletions packages/sdks/nextjs-sdk/src/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ export {
isRefreshTokenExpired,
getJwtPermissions,
getJwtRoles,
getCurrentTenant,
refresh
} from '@descope/react-sdk';
1 change: 1 addition & 0 deletions packages/sdks/nextjs-sdk/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ describe('index', () => {
expect(clientIndex).toHaveProperty('getRefreshToken');
expect(clientIndex).toHaveProperty('isSessionTokenExpired');
expect(clientIndex).toHaveProperty('isRefreshTokenExpired');
expect(clientIndex).toHaveProperty('getCurrentTenant');
expect(clientIndex).toHaveProperty('getJwtPermissions');
expect(clientIndex).toHaveProperty('getJwtRoles');
expect(clientIndex).toHaveProperty('refresh');
Expand Down
1 change: 1 addition & 0 deletions packages/sdks/react-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ You can also use the following functions to assist with various actions managing
`isRefreshTokenExpired(token = getRefreshToken())` - Check whether the current refresh token is expired. Provide a refresh token if is not persisted (see [token persistence](#token-persistence)).
`getJwtRoles(token = getSessionToken(), tenant = '')` - Get current roles from an existing session token. Provide tenant id for specific tenant roles.
`getJwtPermissions(token = getSessionToken(), tenant = '')` - Fet current permissions from an existing session token. Provide tenant id for specific tenant permissions.
`getCurrentTenant(token = getSessionToken())` - Get current tenant id from an existing session token (from the `dct` claim).

### Refresh token lifecycle

Expand Down
1 change: 1 addition & 0 deletions packages/sdks/react-sdk/src/flows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export {
getSessionToken,
isSessionTokenExpired,
isRefreshTokenExpired,
getCurrentTenant,
} from './sdk';

// Export ref to baseHeaders so it can be overridden
Expand Down
4 changes: 4 additions & 0 deletions packages/sdks/react-sdk/src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@ export const getJwtRoles = wrapInTry(
globalSdk?.getJwtRoles(token, tenant),
);

export const getCurrentTenant = wrapInTry(
(token = getSessionToken()) => globalSdk?.getCurrentTenant(token),
);

export const refresh = (token = getRefreshToken()) => globalSdk?.refresh(token);

export const getGlobalSdk = () => globalSdk;
Expand Down
11 changes: 10 additions & 1 deletion packages/sdks/react-sdk/test/utilityFunctions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import createSdk, {
getSessionToken,
isSessionTokenExpired,
isRefreshTokenExpired,
getCurrentTenant,
} from '../src/sdk';

jest.mock('@descope/web-js-sdk', () => () => ({
Expand All @@ -14,6 +15,7 @@ jest.mock('@descope/web-js-sdk', () => () => ({
isJwtExpired: jest.fn(),
getJwtPermissions: jest.fn(),
getJwtRoles: jest.fn(),
getCurrentTenant: jest.fn(),
refresh: jest.fn(),
}));

Expand Down Expand Up @@ -115,12 +117,19 @@ describe('utility functions', () => {
expect(sdk.getJwtRoles).toHaveBeenCalledWith('session', undefined);
});

it('should call getJwtRoles with the session token when not provided', () => {
it('should log error when calling getJwtRoles when the function throws error', () => {
jest.spyOn(console, 'error').mockImplementation(() => {});
jest.spyOn(sdk, 'getJwtRoles').mockImplementation(() => {
throw new Error('session token');
});
getJwtRoles();
expect(console.error).toHaveBeenCalled(); // eslint-disable-line no-console
});

it('should call getCurrentTenant with the session token when not provided', () => {
(sdk.getSessionToken as jest.Mock).mockReturnValueOnce('session-token');
jest.spyOn(sdk, 'getCurrentTenant').mockReturnValueOnce('t-1');
expect(getCurrentTenant()).toBe('t-1');
expect(sdk.getCurrentTenant).toHaveBeenCalledWith('session-token');
});
});
1 change: 1 addition & 0 deletions packages/sdks/vue-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ You can also use the following functions to assist with various actions managing
`isRefreshTokenExpired(token = getRefreshToken())` - Check whether the current refresh token is expired. Provide a refresh token if is not persisted.
`getJwtRoles(token = getSessionToken(), tenant = '')` - Get current roles from an existing session token. Provide tenant id for specific tenant roles.
`getJwtPermissions(token = getSessionToken(), tenant = '')` - Fet current permissions from an existing session token. Provide tenant id for specific tenant permissions.
`getCurrentTenant(token = getSessionToken())` - Get current tenant id from an existing session token (from the `dct` claim).
### Refresh token lifecycle
Expand Down
1 change: 1 addition & 0 deletions packages/sdks/vue-sdk/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ export {
getSessionToken,
isSessionTokenExpired,
isRefreshTokenExpired,
getCurrentTenant,
} from './sdk';
4 changes: 4 additions & 0 deletions packages/sdks/vue-sdk/src/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ export const getJwtRoles = wrapInTry(
globalSdk?.getJwtRoles(token, tenant),
);

export const getCurrentTenant = wrapInTry(
(token = getSessionToken()) => globalSdk?.getCurrentTenant(token),
);

export const refresh = (token = getRefreshToken()) => globalSdk?.refresh(token);

export const getGlobalSdk = () => globalSdk;
Expand Down
11 changes: 10 additions & 1 deletion packages/sdks/vue-sdk/tests/utilityFunctions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import createSdk, {
getSessionToken,
isSessionTokenExpired,
isRefreshTokenExpired,
getCurrentTenant,
} from '../src/sdk';

jest.mock('@descope/web-js-sdk', () => () => ({
Expand All @@ -14,6 +15,7 @@ jest.mock('@descope/web-js-sdk', () => () => ({
isJwtExpired: jest.fn(),
getJwtPermissions: jest.fn(),
getJwtRoles: jest.fn(),
getCurrentTenant: jest.fn(),
refresh: jest.fn(),
}));

Expand Down Expand Up @@ -115,12 +117,19 @@ describe('utility functions', () => {
expect(sdk.getJwtRoles).toHaveBeenCalledWith('session', undefined);
});

it('should call getJwtRoles with the session token when not provided', () => {
it('should log error when calling getJwtRoles when the function throws error', () => {
jest.spyOn(console, 'error').mockImplementation(() => {}); // eslint-disable-line @typescript-eslint/no-empty-function
jest.spyOn(sdk, 'getJwtRoles').mockImplementation(() => {
throw new Error('session token');
});
getJwtRoles();
expect(console.error).toHaveBeenCalled(); // eslint-disable-line no-console
});

it('should call getCurrentTenant with the session token when not provided', () => {
(sdk.getSessionToken as jest.Mock).mockReturnValueOnce('session-token');
jest.spyOn(sdk, 'getCurrentTenant').mockReturnValueOnce('t-1');
expect(getCurrentTenant()).toBe('t-1');
expect(sdk.getCurrentTenant).toHaveBeenCalledWith('session-token');
});
});

0 comments on commit 76e6f6c

Please sign in to comment.