Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
8 changes: 6 additions & 2 deletions src/grants/auth_code.grant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,11 @@ export class AuthCodeGrant extends AbstractAuthorizedGrant {

const bodyScopes = this.getQueryStringParameter("scope", request, []);

const scopes = await this.validateScopes(bodyScopes);
const finalizedScopes = await this.scopeRepository.finalize(
await this.validateScopes(bodyScopes),
this.identifier,
client,
);

const stateParameter = this.getQueryStringParameter("state", request);

Expand All @@ -175,7 +179,7 @@ export class AuthCodeGrant extends AbstractAuthorizedGrant {

authorizationRequest.state = stateParameter;

authorizationRequest.scopes = scopes;
authorizationRequest.scopes = finalizedScopes;

const codeChallenge = this.getQueryStringParameter("code_challenge", request);

Expand Down
26 changes: 25 additions & 1 deletion test/e2e/grants/auth_code.grant.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ describe("authorization_code grant", () => {
let user: OAuthUser;
let client: OAuthClient;
let scope1: OAuthScope;
let scope2: OAuthScope;
let grant: AuthCodeGrant;

let request: OAuthRequest;
Expand All @@ -64,21 +65,23 @@ describe("authorization_code grant", () => {

user = { id: "abc123", email: "jason@example.com" };
scope1 = { name: "scope-1" };
scope2 = { name: "scope-2" };

client = {
id: "authcodeclient",
name: "test auth code client",
secret: undefined,
redirectUris: ["http://example.com"],
allowedGrants: ["authorization_code"],
scopes: [],
scopes: [scope1],
};

grant = createGrant({ issuer: "TestIssuer" });

inMemoryDatabase.clients[client.id] = client;
inMemoryDatabase.users[user.id] = user;
inMemoryDatabase.scopes[scope1.name] = scope1;
inMemoryDatabase.scopes[scope2.name] = scope2;
});

describe("handles response_type for authorization request", () => {
Expand Down Expand Up @@ -140,6 +143,27 @@ describe("authorization_code grant", () => {
expect(authorizationRequest.audience).toStrictEqual(["IAmTheMovie", "CommitToThisMemory"]);
});

it("throws when requesting scope that client should not be able to access", async () => {
request = new OAuthRequest({
query: {
response_type: "code",
client_id: client.id,
// single object arrays is valid
redirect_uri: ["http://example.com"],
state: "state-is-a-secret",
code_challenge: codeChallenge,
code_challenge_method: "S256",
audience: ["IAmTheMovie", "CommitToThisMemory"],
// the client is only allowed to use scope-1
scope: "scope-1 scope-2",
},
});

await expect(() => grant.validateAuthorizationRequest(request)).rejects.toThrowError(
/Unauthorized scope requested by the client: scope-2/,
);
});

it("is successful with plain pkce", async () => {
client.redirectUris = ["http://example.com"];
inMemoryDatabase.clients[client.id] = client;
Expand Down