I have a resource server (built with Flask, but not sure if that matters right now) that has a RESTful API. The API is secured with OAuth2 access tokens and scopes.
Currently the access tokens are opaque (not JWT) and the resource server needs to call the /oauth/token/info endpoint on the auth server to check if the access token is valid and get the list of scopes associated with the access token, and then validate the scopes granted against the ones required. We have some custom code for this.
We now want to start to use JWT access tokens so that we can avoid this call to the auth server, but we can't roll them out to all OAuth clients just yet, only some. So the resource server will be getting a mix of opaque access tokens and JWT access tokens. The JWT will be signed with a RS256 private/public key, and the public key will be available from the auth server at a /oauth/discovery/keys endpoint that the resource servers could hit on startup once and cache so that it doesn't need to hit it on every request, unless the public key changes and doesn't match the kid in the JWT.
While doing this, I was hoping we could get rid of some of the custom code we've written and use some tried and tested library for us, hence AuthLib.
However, I can't seem to find any good examples of how to configure a resource server to handle either of these cases individually, let alone both at the same time. The examples I see seem to assume the resource server has access to the access token database.
I'm assuming I will need to write my own BearerTokenValidator that handles this, but I was hoping there would be examples somewhere on how to go about that. Ideally with the ability to cache the public key for the JWT and only refresh when the JWT kid claim changes.
I was sort of hoping that a TokenInfoBearerTokenValidator and a JWTBearerTokenValidator existed that I could use that did most of the work for me. Maybe there are and I'm just missing it?
AuthLib 1.0 has been released with additional support fro JWTBearerTokens that makes this easier to accomplish now.
I have a general architectural question regarding a new project with microservices based on FastAPI. Looking at it now it’s really not FastAPI specific but here it goes:
How would you make JWT based authentication work between multiple services assuming the following:
You cannot use managed services from AWS etc. like API Gateway (security requirement)
There is a service for user management, which contains username, password etc. and ideally it would allow for JWT authentication
There are other microservices containing app logic for the users stored in the first microservice (from 2.)
In a monolith app this is easy and in a microservice architecture with API gateways it’s also easy but:
how would you approach this (high level) if things kind of hinge on the user management microservice to hold the relevant user data (and in effect being a gateway of its own) where other services should perform actions for those users (based on the JWT token)
tl;dr How would you extend authentication to the other microservices holding the app logic? I think I am overthinking this one and potentially introducing too much coupling :)
If your authentication/user management service issues a JWT, then your other services can rely on that to provide only the allowed data.
The token issued should contain all relevant security info. Let's say you have three types of user: admin, manager, employee. For sake of simplicity let's say this is the only security criteria (you may have multiple criteria in place).
The token can have a field indicating the user permission. As per the OAuth2 spec this is usually done in a scope field. You can create your own custom fields for it anyways.
With the token you can then call your backend services using it. The services will then:
first check the integrity and validity of the token
check the token payload for the scope/permissions and provide the data according to it.
See also the official FastAPI tutorial about using scopes for this purpose with a simple dependency injection.
Answering your comment:
JWT is sadly only within Traefik Enterprise
Maybe you're talking about handling the JWT directly in Traefik, but you should have no trouble passing on the authorization header and deal with the authorization check in the backend service. Plus, you can always embed the token in the request body and totally bypass the reverse proxy.
I have a python application that needs to give users a JSON web token for authentication. The token is built using the PyJWT library (import jwt).
From what I have been reading it seems like an acceptable practice to give the token to a client after they have provided some credentials, such as logging in.
The client then uses that token in the HTTP request header in the Authorization Bearer field which must happen over TLS to ensure the token is not exposed.
The part I do not understand is what if the client exposes that token accidentally? Won't that enable anybody with that token to impersonate them?
What is the most secure way to hand off the token to a client?
You could encrypt the token before handing it off to the client, either using their own public key, or delivering them the key out of band. That secures the delivery, but still does not cover everything.
In short, there's no easy solution. You can perform due diligence and require use of security features, but once the client has decrypted the token, there is still no way to ensure they won't accidentally or otherwise expose it anyway. Good security requires both participants practice good habits.
The nice thing about tokens is you can just give them a preset lifespan, or easily revoke them and generate new ones if you suspect they have been compromised.
Token will be build based on user provided information and what you back-end decided to be part of the token. For higher security you can just widen your token information to some specific data of the user like current ip address or device mac address, this will give you a more secure way of authentication but will restrict user to every time use the same device, as a matter you can send a confirmation email when a new login happens.
I'm planning to write a Kodi (former XBMC) plugin for Spotify using Python. Some time ago, Spotify deprecated their old library libspotify and introduced a new ReST based WebAPI. I would like to use this api to request data like the playlists, followed albums and other user specific stuff from Spotify. This WebAPI uses the OAUTH mechanism to authorize an application to use user-specific data.
Thus, I require a Client ID and a Client Secret. While the Client ID is public I have not problem in storing it in the sourcecode. But what about the Client Secret? This secret is required by the application to authenticate itself at spotify. Thus, it needs to be deployed as well.
How do I securly deploy this secret, such that a user of the plugin is not able to read out the secret?
I can't use obfuscation techniques because python is interpreted and a user can simply start an interpreter, import my modules and read out the reconstructed secret. The same holds for encrypting the key. The application needs to be able to decrypt the secret and because of this, I would need to deploy the encryption key as well. This is a chicken or egg problem.
Any suggestions about this? How does other software solve this problem?
EDIT: I just found this RFC6819. Seems like this is a general problem in oauth.
In this case, you can use the Implicit Grant Flow, which is designed for client-side applications where storing the secret is impractical for security reasons.
I'm writing an oauth2 provider and am not sure how to implement client registration. The oauth2 specification doesn't cover this aspect:
The means through which the client registers with the authorization server are beyond the scope of this specification but typically involve end-user interaction with an HTML registration form.
Moreover, the oauthlib documentation has the following to say about the Client data model:
It is common practice to link each client with one of your existing users. Whether you do associate clients and users or not, ensure you are able to protect yourself against malicious clients.
Now I sure would love to protect myself against malicious clients, but how can I link a client to a user if registering a user requires a registered client?
The oauth2 spec again has something to say about this, but it's very cryptic:
Client registration does not require a direct interaction between the client and the authorization server. When supported by the authorization server, registration can rely on other means for establishing trust and obtaining the required client properties (e.g., redirection URI, client type). For example, registration can be accomplished using a self-issued or third-party-issued assertion, or by the authorization server performing client discovery using a trusted channel.
Questions
How should a client be registered if linking to a user is required, given that registering a user requires a registered client?
How should a client be registered if linking to a user is not required? What is meant by 'redirection URI, client type, and third-party-issued assertion?
When answering this question, I am going to assume there is already an access control framework that this provider will be attached to, and the application that will use this provider will have HTTP access and has capabilities to handle HTML forms, as no details on this whatsoever were provided by the question (i.e. what framework is this provider going to sit on, or is it something completely naked and standalone on some homebrewed framework).
I'm writing an oauth2 provider and am not sure how to implement client registration. The oauth2 specification doesn't cover this aspect:
The means through which the client registers with the authorization server are beyond the scope of this specification but typically involve end-user interaction with an HTML registration form.
While it doesn't spell it out explicitly, it did suggest that typical registration of a client involves end-user interaction with a form. If you see how others have done it (such as through imgur's API, OAuth 2 user documentation) you will find that it provides a Registration link and hey that's how clients are registered. No OAuth 2 is required as you are already authenticated via the browser.
Now I sure would love to protect myself against malicious clients, but how can I link a client to a user
By linking your server applications's representation of the client details to the user (tracked by some system) that created those client details? It's not like user specific data suddenly becomes more mystical just because it is used for authenticating an OAuth2 client. If you find abuse related to access using those client details (from your logs) you could just revoke those credentials related to that client, and punish the user that own that client. (Unless it's their clients... erm, your other users using that client is doing the abuse but you should be able to see that, right?)
if registering a user requires a registered client?
If you really want to have people register their clients using their client before they register their client, that's pretty much madness (i.e. a chicken and egg problem that shouldn't need to exist). Nowhere in the specification this was ever suggested that they are mutually inclusive problems. Here, to simplify this:
You can use a registered client to register a user
You can register a client to a registered user
Those two things are completely separate from each other. You have to have one before the other (actually, you can create a user registration form that also generates a client credentials at the same time, but I digress), but really, a registered client is essentially reducible to some credentials that are shared between that client and the provider it is registered against.
You can make your own registered clients, too, since you have full control of the provider, you can inject any credentials that will be used by that registered client of yours to do whatever you need, including registering new users, but...
How should a client be registered if linking to a user is required, given that registering a user requires a registered client?
You know you can just register a user using a standard HTML registration form? Just use the user registration form that the framework provided, or write one* if that framework doesn't already provide one.
How should a client be registered if linking to a user is not required?
When I implemented an OAuth1 provider for Plone, client registration can only be done by administrators/managers of the site, so not something user can do, thus someone has to contact the owners of the site to find out how to do it. This generally removes the security problems associated with not linking clients to users (since clients are now linked to actual people coding those clients up who are not necessarily users of the site through external means).
I realized I did not really answer this question, but this is really up to your implementation and what needs/restrictions you decide to limit/provide. I mean you can have a totally anonymous form on your site and let it rip, but I don't think you want that as that weakens security of your application dramatically.
What is meant by 'redirection URI, client type, and third-party-issued assertion?
If you go to the sections as specified in the RFC, you will find answers there:
Redirection URI
There is actually quite a lot of ways to subvert the security of your users' (resource owner's) data if this is not carefully understood, but is used by the authorization server to "redirects the resource owner's user-agent back to the client", as the authorization is done on the authorization server which is part of the provider's infrastructure. So in general, the client has to let the authorization server know where/how it gets back to itself after the resource owner authorizes the client's access through this redirection URI. However, if the redirection URI specified is not verified, security issues can and will happen.
For instance, native applications (a client profile of the client type public) will (used to, I am coming from an OAuth1 background) have the complete client credentials embedded inside the application, which will be extracted by hostile attackers in a bid to masquerade as a legitimate web application (another client profile, but can be considered as a confidential client type) that makes use of your application's services. Once the hostile attackers are up and running they will entice your users (resource owners) to use their masqueraded site, and grant the masqueraded site their access tokens through your authorization server and if redirection URIs are not validated, it will redirect your users (resource owners) to the attacker with the authorization code (as outlined in section 1.3), giving the attacker access to your resource owner's data.
That was the easy common case - another problem case is that your other web application client might have a credential leak without them knowing, resulting in this exact scenario.
Hence this is why they suggest that you should only "redirect the user-agent to the client's redirection endpoint previously established with the authorization server during the client registration process... after completing its interaction with the resource owner", which can mean that only the domain name registered to that client will be legitimate redirection targets, otherwise something went wrong and your authorization server aborts and does not provide the authorization grant.
Client Types
Again, just read/scrutinize all that carefully.
Third-party-issued assertion
As opposed to self-issued client registration done kind of like a client registration form, your application might delegate the client authentication to a third party which will do the verification for you. If you have to worry about this and don't know where to start I suggest you ignore this and just only do self-issued client.
* Are you really sure you want to write an OAuth2 provider without any underlying user/ACL framework for you to hook this to? I mean you can write one but you should really build that part first before you worry about OAuth2 (again, I am not making any assertion, since the question provided no information on this).
Now, if you are not doing this as part of some existing framework but just something standalone that you want to toy/try out as learning, I strongly suggest you to pick something else because this is probably beyond what you can do in a correct manner. Especially if you don't already fully understand the implication of this with regards to the underlying ACL and security of the resource owner's data, and other related stuff.
No offense, but these things are very very difficult to do correctly. Even the bigger companies have had security issues with their OAuth2 solutions.
Finally, speaking from experience, I spent about four (4) weeks (!) staring at the OAuth1 specification years ago, using a poorly written Python OAuth library (later replaced with oauthlib, which is much better) in an attempt to build an OAuth1 provider on top of Plone, before I got a single line of code directly related to the provider committed. A lot of junk/trial code written was thrown away, and this was done because understanding all of this stuff actually took time (granted, I was not exactly working full time on this, had other responsibilities too which was distracting me from this). Another part of the time was spent trying to understand how the user/security stuff is put together at the Zope/Plone layer. Granted I was still relatively new to that side of that framework, but I can guarantee you that this road is not going to be easy... however I did seem to find that OAuth 2 cleaned things up in some ways to make it easier to understand, but find that the security may have been weakened. That said, I currently have no immediate plans to port my Plone addon to support 2.0 as my sponsors does not require that, so there may be things I suggested up there that may differ slightly from 2.0. Would love to hear your comments if others have read this far. I wrote way more words than I originally intended to, oops.
Anyway, good luck on your adventures.
Additionaly for dynamic registration, please go through this spec as well
https://www.rfc-editor.org/rfc/rfc7592