Skip to content

Commit 41670f1

Browse files
authored
Merge pull request #164 from dahlia/fix/163
Allow extra parameters in `POST /oauth/token`
2 parents 7fcdd27 + b8d5db9 commit 41670f1

3 files changed

Lines changed: 67 additions & 9 deletions

File tree

CHANGES.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,16 @@ Version 0.6.1
66

77
To be released.
88

9+
- Fixed `POST /oauth/token` endpoint rejecting requests with additional
10+
parameters not required by RFC 6749 but commonly sent by clients.
11+
The endpoint now gracefully ignores extra parameters like `scope` in
12+
`authorization_code` requests and `redirect_uri` in `client_credentials`
13+
requests instead of returning validation errors.
14+
[[#163], [#164] by Hong Minhee]
15+
16+
[#163]: https://github.com/fedify-dev/hollo/issues/163
17+
[#164]: https://github.com/fedify-dev/hollo/pull/164
18+
919

1020
Version 0.6.0
1121
-------------

src/oauth.test.ts

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1368,12 +1368,21 @@ describe.sequential("OAuth", () => {
13681368
expect(responseBody.error).toBe("unsupported_grant_type");
13691369
});
13701370

1371-
// Invalid request
1372-
it("cannot use unknown parameters", async () => {
1373-
expect.assertions(4);
1371+
it("can accept scope for authorization_code requests", async () => {
1372+
expect.assertions(7);
1373+
1374+
const accessGrant = await createAccessGrant(
1375+
application.id,
1376+
account.id,
1377+
["read:accounts"],
1378+
OOB_REDIRECT_URI,
1379+
);
1380+
13741381
const body = new FormData();
1375-
body.set("grant_type", "client_credentials");
1382+
body.set("grant_type", "authorization_code");
13761383
body.set("redirect_uri", OOB_REDIRECT_URI);
1384+
body.set("code", accessGrant.code);
1385+
body.set("scope", "follow");
13771386

13781387
const response = await app.request("/oauth/token", {
13791388
method: "POST",
@@ -1383,13 +1392,44 @@ describe.sequential("OAuth", () => {
13831392
body,
13841393
});
13851394

1386-
expect(response.status).toBe(400);
1387-
expect(response.headers.get("content-type")).toBe("application/json");
1395+
expect(response.status).toBe(200);
1396+
expect(response.headers.get("Content-Type")).toBe("application/json");
13881397

13891398
const responseBody = await response.json();
1399+
expect(typeof responseBody).toBe("object");
1400+
expect(responseBody).toHaveProperty("access_token");
1401+
expect(responseBody).toHaveProperty("created_at");
1402+
expect(responseBody.scope).toBe("read:accounts");
1403+
expect(responseBody.token_type).toBe("Bearer");
1404+
});
13901405

1406+
it("can accept redirect_uri for client_credentials requests", async () => {
1407+
expect.assertions(7);
1408+
1409+
const body = new FormData();
1410+
body.set("grant_type", "client_credentials");
1411+
body.set("scope", "read:accounts");
1412+
body.set("redirect_uri", OOB_REDIRECT_URI);
1413+
1414+
const response = await app.request("/oauth/token", {
1415+
method: "POST",
1416+
headers: {
1417+
authorization: basicAuthorization(application),
1418+
},
1419+
body,
1420+
});
1421+
1422+
// No redirection happens here, since redirect_uri is not used in
1423+
// client_credentials flow, so we expect a 200 OK response:
1424+
expect(response.status).toBe(200);
1425+
expect(response.headers.get("Content-Type")).toBe("application/json");
1426+
1427+
const responseBody = await response.json();
13911428
expect(typeof responseBody).toBe("object");
1392-
expect(responseBody.error).toBe("invalid_request");
1429+
expect(responseBody).toHaveProperty("access_token");
1430+
expect(responseBody).toHaveProperty("created_at");
1431+
expect(responseBody.scope).toBe("read:accounts");
1432+
expect(responseBody.token_type).toBe("Bearer");
13931433
});
13941434
});
13951435

src/oauth.tsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,15 +213,23 @@ const INVALID_GRANT_ERROR = {
213213
};
214214

215215
const tokenRequestSchema = z.discriminatedUnion("grant_type", [
216-
z.strictObject({
216+
// Use z.object() instead of z.strictObject() to allow clients to send
217+
// additional parameters like 'redirect_uri' which are commonly sent but not
218+
// required by RFC 6749 for client_credentials grant type.
219+
// See also <https://github.com/fedify-dev/hollo/issues/163>:
220+
z.object({
217221
grant_type: z.literal("client_credentials"),
218222
scope: scopesSchema.optional(),
219223
// client_id and client_secret are present but consumed by the
220224
// clientAuthentication middleware:
221225
client_id: z.string().optional(),
222226
client_secret: z.string().optional(),
223227
}),
224-
z.strictObject({
228+
// Use z.object() instead of z.strictObject() to allow clients to send
229+
// additional parameters like 'scope' which are commonly sent but not
230+
// required by RFC 6749 for authorization_code grant type.
231+
// See also <https://github.com/fedify-dev/hollo/issues/163>:
232+
z.object({
225233
grant_type: z.literal("authorization_code"),
226234
redirect_uri: z.string().url(),
227235
code: z.string(),

0 commit comments

Comments
 (0)