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

More usage applicable documentation #137

Open
sidju opened this issue Nov 15, 2023 · 3 comments
Open

More usage applicable documentation #137

sidju opened this issue Nov 15, 2023 · 3 comments

Comments

@sidju
Copy link

sidju commented Nov 15, 2023

The current documentation showcases how to communicate with the Authentication Provider and verify the responses, but it doesn't mention a lot of how to build an authentication flow on it.

I'm very uncertain about these answers (as the best I can find is implications that something similar is done by a different OIDC implementation and no real examples), but I'll at least suggest the questions I've had while trying to implement an authentication with this library:

  • What part of the TokenResponse should be used for what.
    (the .access_token() is the oauth part of the response that allows the OIDC client to prove the users permission to act in their stead, the .extra_fields().id_token() is the OIDC part of the response with data for the default claims and the claims configured for the OIDC client)
  • How does the validation of the IdToken claims through .claims() work. Are the claims encrypted, how tamper-proof are they?
    (It seems like JWTs are generally asymmetrically encrypted, but the main relevant documentation would be how tamper proof they are and how the algorithm matters. Also more should be specified about Nonce and why it is required, not only that it is strongly recommended.)
  • And related to that, how the Nonce should be used. Should you verify the Nonce on the IdToken the first time or every time? Is there a way to not need to do it again? If needed to do it every time, how should you store the Nonce?
    (There seems to be a standard of verifying the Nonce every time, since one often stores the IdToken in locations that aren't tamper proof and wish to verify that it hasn't been replaced by another (still signed and valid) IdToken with different properties. To enable this one should either maintain internal state with the Nonce or save an opaque cookie to the user's browser which after hashing or decryption equals the Nonce. The latter is not secure for client side applications, as they cannot prevent attackers reading out their hashing algorithm or encryption key from the executing code, so they should store the Nonce as is internally instead of making it accessible for modification by others through a cookie.)
  • How to store the TokenResponse in normal applications.
    • The access_token should not be stored in a cookie at any point, as it is an API key as is. Server side applications should store it in their database keyed to an opaque user identifier which is stored in a cookie, to prevent a sniffed web request leaking the API key. Client side applications should store it internally with extra attention to preventing access from other local code, multiple approaches are documented on the web.
    • The id_token is more generally fine to store, but one should be wary of the sensitivity of the data it contains as it isn't encrypted and therefore readable to everyone with access to the storage location.

That is what I've figure this far, from a lot of research. It would be nice if this information was available on the types it relates to or in the examples. Just some quick hints in the style of:

  • "the nonce and csrf should be stored in application state to verify different steps in the authentication flow",
  • "the access_token is the API key enabling you to act in the user's stead (note the token_type which specifies how to use it, usually bearer)"

If you can confirm this is something you want I can make a PR. I've clearly already written half of what I wanted to add.

@ramosbugs
Copy link
Owner

Hey @sidju,

Thanks for this feedback. I've had to spend so much time buried in the specs to write this crate (and oauth2) that it's difficult to look at the docs from a fresh end user's perspective.

Many of the questions you raised (e.g., "Are the claims encrypted, how tamper-proof are they?") are about the OIDC protocol in general, and not specific to this crate's interfaces. Answers to those questions already exist in the specs and various implementation-agnostic resources around the web. I don't think the documentation for every library in every programming language should attempt to fully explain the protocol, just as HTTP client libraries don't attempt to explain HTTP itself to their users.

Given that this protocol is for security-critical functionality, I would expect users to learn enough about the protocol to answer basic questions like "is my use case a confidential client that can store a client_secret?" and "which auth flow should I use?" before approaching this library to implement their desired auth flow. This crate attempts to express as many of the protocol's security requirements within Rust's type system as possible, but it doesn't abstract away the inherent security considerations that users still need to be aware of when implementing authentication in their applications. Consequently, I think the goal of this crate's documentation should be to help users go from an understanding of their desired auth flow to a secure implementation as easily as possible, not to serve as the only resource users need to consult when building auth.

This doesn't mean I think the current docs can't be improved significantly. They could, for example, explicitly list the decisions (e.g., choice of auth flow) users need to make before trying to use the library, along with links to good resources containing the information they'll need to make those decisions.

The sorts of hints you listed would also be a nice addition as a reminder to users what certain types are used for. We should be careful not to be overly prescriptive though, since, for example, the CSRF token and nonce could also be stored in a cookie depending on the type of application the user is working on. This is another good opportunity for links to external resources that discuss the various storage options and their tradeoffs.

@sidju
Copy link
Author

sidju commented Nov 16, 2023

Thank you for the quick response.

That is a very reasonable limitation of scope and expectation on the users.

I'll see if I can make a PR with some additional comments in the examples (mainly which type comes out and why, as that is a bit difficult to parse with all the type arguments the Client takes), maybe some getting started information in the crate documentation, and some extra documentation on the types. Mainly how you are expected to get an instance of a type and which type is the typical implementer of a trait should be documented, as there are so many types implementing so many traits that it is easy to get lost looking for a method in a trait that is implemented on a type.

@ramosbugs
Copy link
Owner

That sounds great, thanks!

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

No branches or pull requests

2 participants