-
-
Notifications
You must be signed in to change notification settings - Fork 27
Implement access grants for OAuth #130
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Implement access grants for OAuth #130
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some informative comments.
Code coverage for src/oauth.tsx
is 56.47%, and for the other parts:
hollo/src/oauth | 83.18 | 79.16 | 85.71 | 83.18 |
constants.ts | 100 | 100 | 100 | 100 |
helpers.ts | 78.16 | 57.14 | 80 | 78.16 | 40-59,92-98,131-134
middleware.ts | 98.52 | 93.33 | 100 | 98.52 | 61
validators.ts | 66.66 | 50 | 100 | 66.66 | 11-17
// This is necessary for passing a transaction into a function: | ||
export type Transaction = PgTransaction< | ||
PostgresJsQueryResultHKT, | ||
typeof schema, | ||
ExtractTablesWithRelations<typeof schema> | ||
>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently drizzle doesn't export a type for this, which is weird.
t.assert.equal( | ||
response.headers.get("Location"), | ||
"custom://oauth_callback?error=access_denied&error_description=The+resource+owner+or+authorization+server+denied+the+request.", | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I could maybe assert here that the count of access grants is zero?
src/oauth.tsx
Outdated
// Revoke the access grant: | ||
await tx | ||
.update(accessGrants) | ||
.set({ | ||
revokedAt: new Date(), | ||
}) | ||
.where(eq(accessGrants.token, accessGrantToken)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently I'm setting revokedAt
here, which means our database will have loads of now useless access grants in it. It would be a reasonable decision to just delete the access grant from the database in this case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dahlia would like your thoughts here, a trade-off is that by not setting revoked
and just deleting the access grant, you can't detect authorization code reuse attacks, where the authorization code is reused and consequently all created access tokens from that authorization code should be invalidated (grants, this would imply having some relationship between access grants and access tokens)
@@ -272,18 +292,9 @@ app.post("/token", cors(), async (c) => { | |||
401, | |||
); | |||
} | |||
if (form.scope?.some((s) => !application.scopes.includes(s))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
scope
is only required for client_credentials
grant type.
it( | ||
"Returns an error if the access token is not valid", | ||
{ plan: 3 }, | ||
async (t: TestContext) => { | ||
const response = await app.request("/endpoint", { | ||
method: "GET", | ||
headers: { | ||
// Forces the Access Token code path: | ||
Authorization: "Bearer foo^bar", | ||
}, | ||
}); | ||
|
||
t.assert.equal(response.status, 401, "Should return 401"); | ||
t.assert.equal(response.headers.get("content-type"), "application/json"); | ||
|
||
const json = await response.json(); | ||
|
||
t.assert.equal(json.error, "invalid_token"); | ||
}, | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code path technically doesn't exist anymore, so we could remove this test.
"test": "pnpm run migrate:test && tsx --env-file-if-exists=.env.test --test --test-concurrency=1", | ||
"test:ci": "tsx --test --test-reporter=@reporters/github --test-reporter-destination=stdout --test-reporter=spec --test-reporter-destination=stdout --test-concurrency=1", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We needed to switch to concurrency of 1 for now, as the database tests clean the database, which causes issues if multiple tests are running concurrently.
"check": "tsc && biome check .", | ||
"check:ci": "tsc && biome ci --reporter=github .", | ||
"check:coverage": "c8 --check-coverage --lines 100 pnpm test -- --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=coverage/tmp/lcov.info", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now, this is just to give an idea of where we stand, but we may want to make it part of CI to check code coverage once we get it high enough.
Could probably also already include it as like a PR comment or something.
Correction, oauth coverage is, I had some dead code:
|
fd5e2e6
to
9481a4b
Compare
… type flow Mastodon apparently supports passing scopes to /oauth/token endpoint
ec19c6c
to
66e347e
Compare
@dahlia I've just been working on the access tokens for FIRES, and came across something interesting, which is still using a database value for the "secret values", but using a construction of Might be an idea to adopt that. I've also come across some interesting stuff for including CRC32's at the end of the token, such that secret scanning tools can easily detect the secret is a "valid secret": https://docs.github.com/en/code-security/secret-scanning/secret-scanning-partnership-program/secret-scanning-partner-program#identify-your-secrets-and-create-regular-expressions |
This is still a work in progress, but gives an idea of how the code changes. I haven't yet implemented PKCE in here, though the database supports it.