Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/auth0-server-js/src/server-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
AuthorizationDetails,
TokenByRefreshTokenError,
} from '@auth0/auth0-auth-js';
import { compareScopes } from './utils.js';

export class ServerClient<TStoreOptions = unknown> {
readonly #options: ServerClientOptions<TStoreOptions>;
Expand Down Expand Up @@ -335,7 +336,7 @@ export class ServerClient<TStoreOptions = unknown> {
const scope = this.#options.authorizationParams?.scope;

const tokenSet = stateData?.tokenSets.find(
(tokenSet) => tokenSet.audience === audience && (!scope || tokenSet.scope === scope)
(tokenSet) => tokenSet.audience === audience && (!scope || compareScopes(tokenSet.scope, scope))
);

if (tokenSet && tokenSet.expiresAt > Date.now() / 1000) {
Expand Down
58 changes: 58 additions & 0 deletions packages/auth0-server-js/src/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { expect, test } from 'vitest';
import { compareScopes } from './utils.js';

test('should match scopes when more scopes are available', () => {
const scopes = 'a b';
const requiredScopes = 'a';

expect(compareScopes(scopes, requiredScopes)).toBe(true);
});

test('should match exact scopes', () => {
const scopes = 'a b';
const requiredScopes = 'a b';

expect(compareScopes(scopes, requiredScopes)).toBe(true);
});

test('should match exact scopes in reverse order', () => {
const scopes = 'a b';
const requiredScopes = 'b a';

expect(compareScopes(scopes, requiredScopes)).toBe(true);
});

test('should match when both empty', () => {
const scopes = '';
const requiredScopes = '';

expect(compareScopes(scopes, requiredScopes)).toBe(true);
});

test('should not match when scopes empty', () => {
const scopes = '';
const requiredScopes = 'a b c d';

expect(compareScopes(scopes, requiredScopes)).toBe(false);
});

test('should not match when requiredScopes empty', () => {
const scopes = 'a b';
const requiredScopes = '';

expect(compareScopes(scopes, requiredScopes)).toBe(false);
});

test('should not match when no scope included', () => {
const scopes = 'a b';
const requiredScopes = 'c d';

expect(compareScopes(scopes, requiredScopes)).toBe(false);
});

test('should not match when some scopes not included', () => {
const scopes = 'a b';
const requiredScopes = 'a b c d';

expect(compareScopes(scopes, requiredScopes)).toBe(false);
});
Comment thread
frederikprijck marked this conversation as resolved.
20 changes: 20 additions & 0 deletions packages/auth0-server-js/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/**
* Compares two sets of scopes to determine if all required scopes are present in the provided scopes.
* @param scopes Scopes to compare
* @param requiredScopes Scopes required to be present in the scopes
* @returns True if all required scopes are present in the scopes, false otherwise
*/
export const compareScopes = (scopes: string | undefined, requiredScopes: string | undefined) => {
if (!scopes && !requiredScopes) {
Comment thread
frederikprijck marked this conversation as resolved.
Outdated
return true;
}

if (!scopes || !requiredScopes) {
return false;
}

const scopesArray = scopes.split(' ');
Comment thread
frederikprijck marked this conversation as resolved.
Outdated
const requiredScopesArray = requiredScopes.split(' ');

return requiredScopesArray.every((scope) => scopesArray.includes(scope));
Comment thread
frederikprijck marked this conversation as resolved.
Outdated
};