Skip to content
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

OAuth #42

Draft
wants to merge 23 commits into
base: main
Choose a base branch
from
Draft

OAuth #42

wants to merge 23 commits into from

Conversation

DavidBuchanan314
Copy link
Owner

@DavidBuchanan314 DavidBuchanan314 commented Jan 17, 2025

It's happening. Will close #15

TODO:

  • DPoP JTI replay prevention
  • OAuth token refresh
  • Strict PAR validation
  • Strict client metadata validation
  • Think about what happens when login_hint doesn't match the currently logged-in user?
  • Belt-and-braces CSRF prevention (add CSRF tokens even though I don't think we actually need them?)
  • Reading over the spec again carefully to make sure I haven't missed anything
  • Think carefully about things like login CSRF, session fixation
  • Tests!!!!

@DavidBuchanan314
Copy link
Owner Author

Problem: to prevent CSRF, I'm using samesite=Strict on the cookie. However, this means that when a client redirects to the authz page for the first time, it doesn't "see" the cookie. We could probably fix it with an extra redirect hop, but can we do it without a redirect?

Also, the authn->authz redirect is janky, there's a flash of white for the HTML redirect. Aside from adding CSS, not sure what to do about that.

@DavidBuchanan314
Copy link
Owner Author

DavidBuchanan314 commented Jan 18, 2025

def authorization {
    look at the PAR'd authorization request document, perform initial checks, pull out the login hint
    
    if not authenticated:
       redirect to login page (and come back to authz flow once that's done)
    
    request the client metadata
    
    if various security checks fail:
       bail out to error page
    
    if the required scopes aren't yet granted by the user:
       redirect to scope granting page (and come back to authz flow once that's done)
       
    if various security checks fail:
       bail out to error page
       
    redirect back to the client with an auth code
}

There's a problem with this approach: we request the client metadata document twice (if the scopes weren't already granted). Is that actually a problem though? perf-wise we can solve this with caching, and security-wise I'm not sure it's an issue. the full security checks will still be applied in the final run through the flow, before handing over the auth code to the client (i.e. I don't think there's any TOCTOU risk).

We could request client metadata during PAR and store it alongside it???? but that means the request happens pre-auth...

@DavidBuchanan314
Copy link
Owner Author

I think I can use HTTP 303 to solve the POST->GET redirect issues https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/303

@DavidBuchanan314
Copy link
Owner Author

DavidBuchanan314 commented Jan 19, 2025

Main outstanding issues:

  • Make authorization grant flow work properly

  • Lots and lots of missing security checks (including dpop, preventing CSRF)

I also had an idea. Since bsky.app has no built-in mechanism for managing oauth permissions and sessions, I was thinking of hacking up the "app password" list API and turning into a thing for revoking permissions granted to clients.

@DavidBuchanan314
Copy link
Owner Author

I think for DPoP I'm going to want to add another middleware. If the dpop header is present, it'll verify it, check for replays, and set request["dpop_jkt"]. For endpoints requiring dpop binding, I can check it manually. The auth decorator can check it likewise.

@DavidBuchanan314
Copy link
Owner Author

I also want to refactor authentication into a middleware that conditionally populates request["authed_did"] and request["authed_scopes"], and a decorator that asserts a given set of scopes are present.

@DavidBuchanan314
Copy link
Owner Author

We need to make sure that both service proxying and getServiceAuth can't bypass a lack of transition:chat.bsky scope

@DavidBuchanan314
Copy link
Owner Author

We need to make sure refreshSession/deleteSession only work for sessions started via password auth. And, we need to make the oauth-only refresh/delete endpoints work.

@DavidBuchanan314
Copy link
Owner Author

DavidBuchanan314 commented Jan 23, 2025

Because I check for JTI revocation via db on every request (either password auth or oauth tokens), I'm wondering if there's much value in using JWTs in the first place (since I'm not really taking advantage of statelessness). What if I just use uuid tokens instead? I think I'll continue using JWTs for now but it's worth thinking about as a potential simplification for the future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

OAuth Stuff
1 participant