IdentityServer4 personal access token (github-like) or API key for third party clients - authentication

Our current setup is
IdentityServer4
Angular + ASP.NET Core application
Authentication for the app via implicit flow/oidc.
We want to provide APIs for customers, i.e. third party clients, with restricted access (separate set/subset of claims). These clients are mostly non-interactive scripts that download data.
This means that we cannot use any flow which (occasionally) requires user interaction. Personal access tokens, like in github, or some other generate once, reuse for a long time API key or token would be needed.
The long token lifetime would not be a security issue, because the token should only allow access to a few read-only APIs and only for that customer's data - so the responsibility to handle the token(s) falls onto the customer.
The customer should be able to create and revoke such API-access tokens based on their claims. Some users might only claims to access certain APIs.
It would be good if we could later prevent that the user re-uses the same token for multiple clients because of licensing requirements but that is perhaps an entirely new question
How could I achieve this?
I thought about doing this via a custom grant, similar to a delegation grant: user uses app, which calls the asp.net core API, which performs auth with that custom grant, persists that token somewhere (just a plain table in the database full of customer-api-only tokens? I'm not sure about that) and shows it to the user - which can also retrieve it later from storage.
I'm thinking about doing the "delegate"-authentication via our API so that we don't leak the secrets into the Angular application.
I think that we then should be able to have either long-lived access tokens or at least refresh tokens via that custom grant.
2017-12-12 how I think I could solve it
We want a process where the user generates something in our application (i.e. via our client) and this something can later be used by the user's third party client to access the API - or request an access token and then access the API.
We want this access to be tied to the user. This includes
- Disabled user
- Lockout
- Specific claims (e.g. tenant)
This does not lend itself well to a solution that issues access tokens directly, because the token would remain valid even if the user was disabled or locked out. Which means that we cannot use a custom grant or IdentityServerTools to issue tokens directly.
Therefore we should use the client credentials grant, or something similar to it, as this could yield new, short-lived access tokens.
User actually generates a new client, which is pre-filled with claims from the user (such as the tenant - which is immutable) and has a claim that corresponds with the user. This happens transparently. Password should be user-supplied with the option to change it. We only store the relation between user and issued client-ids, no passwords.
We have to create a custom grant, which works similar to client credentials, but also checks if the corresponding user is active etc. (which I think should be possible by injecting UserManager)
Resulting access token lifetime is short, interaction with our APIs is expected to be short-lived.
Assuming it is safe and easy enough to write such a grant, we should be able to cover everything we need.
Of course, I might have completely overlooked something :)

Related

OAuth implementation including login using internal database

I want to include the oauth2 authentication flow into my application, but also provide an internal database (regular register / login) as an authentication method.
I'm not that sure how to approach that behavior, as I would love to have one single state for the authentication. I've thought about exposing the authentication using the internal database as an OAuth2 application itself, therefor token management etc can be generalized.
This would be a basic example of my thought process:
To distinguish between the multiple OAuth providers, I'd have wrapped the actual token inside a JWT, which also contains the providers name (as well as have a spam protection in my backend, instead of spamming the actual provider).
I'm not sure if it's that good to store the actual user data in a database as well - But I'd need some kind of overview of registered users for the administrators to see - and maybe block or delete.
My questions in particular:
Should the OAuth token be wrapped in a JWT for identification of the provider?
Is it bad practice to store the user data in a database as well? (If not, how much data should be stored [username, ...] and when should the data be refreshed?)
Is there anything else I should keep in mind when doing the authentication flow as it is?

Is JWT right for me?

I've done a fair amount of research on the many different ways to authenticate and authorize users who use my frontend application to access my REST API. I've built a system that uses OAuth2 and JWT and need a sanity check since I'm working on this alone.
For a bit of background, my frontend is built using Vue.js and my API is built using Django with Django Rest Framework. My team is already planning on concurrently developing the mobile and desktop versions of this app which both would require authentication and authorization as well.
To keep things brief, I'll omit the alternative solutions I have and just talk about the most controversial one.
Right now, OAuth2 (my authorization server) grants users a JWT token using ROPC when they provide their email and password to my frontend client. I should note that my API (my resource server) and authorization server live on the same machine.
My application allows users to essentially signup using different plans (for example a free plan and a paid plan). When a user signs up for a free plan, I need the frontend application to not only disable certain features and elements in the UI, but also I need the authorization server and or resource server to limit what that user is allowed to query based on their plan.
The idea is when a user signs up or logs in, my authorization server will get the associated user record from the database and create a valid JWT with a claim attached that states the user's plan and maybe some other non-personal information. Then once signed it sends it off to the user where the frontend can enable/disable parts of the UI... etc. Hence, if a user logs in on mobile, we can customize the UI based on the same claim sent by the JWT.
My issue is that I don't know if this is a good way to go about it. It seems that everyone I've asked in my circle is split on using JWT or not. Those apposed mostly raise security issues, but, when from what I understand, many of the JWT security pitfalls are well documented and can be avoided just using some commonsense as with any other session/token-based authentication. I'm starting to get analysis paralysis. Please help.
CLASSIFICATION
I would say this is really an API Authorization question, as opposed to an OAuth question:
The role of the Authorization Server and tokens is really just to prove the user's identity
Product specific logic comes after the user logs in and is generally best handled in your app
MY PREFERENCES
Here is how I would handle it:
Save the plan type to your product data when the user signs up
After login, look up the user from the access token
Then look up the user's plan type from your product data
Produce a Claims / Principal object in your API containing both
Enforce business rules based on the plan type claim
I would aim for a Claims object something like this:
class ApiClaims {
// The user id in the access token
userId: string;
// The email
email: string;
// The plan type
planType: string;
// Other claims from the token
// Other claims from product data, eg user roles
}
RESOURCES
If interested in this approach, these blog posts of mine may be of interest:
User Data Management
API Authorization
JWT?
You need some kind of API credential that is sent in HTTPS messages and is web and mobile friendly, so I would use JWTs. You could follow the same pattern with any API credential though.
It depends on what you are trying to protect of course, but JWT bearer tokens are an industry standard. Since you control both the client and the authorization server, you can implement it however you like.
I would look into changing Resource Owner Password Credentials flow to authorization code flow. It will enable you to use social authentication providers like Google or Facebook to sign in users (while still maintaining plan info in your own service). Chances are that people trust those companies more to keep their credentials safe than your company, and it allows you to benefit from any authentication features (MFA) those companies implement.
Also, if you want the clients to read the contents of the token, you should use OpenID Connect id_tokens, as those are guarenteed to be in JWT format.

How can I define policies for my API for two types of access tokens, one with an identity (sub) and one without?

I am using IdentityServer4 via ASPNET Core, and I want users to access my API both by the web browser via their identity (Implicit and Hybrid), and by clients programatically (Client Credentials). I realize all I have to do is add AddIdentityServerAuthentication and I am done. However, that only solves the authentication aspect of this problem, not the authorization.
Authorization:
With ASPNET Core, you can just use Role based auth (or PolicyServer permissions which is similar) but only if you have an identity with role claims, that does not work for client credentials. So that brings us to needing to secure by role, or policies AND by scopes. How can I do this?
You cant have multiple policies, if you do, they both must pass.
You can't have multiple auth schemes, because my call to AddIdentityServerAuthentication will have to use the same authority, so how would IdentityServer4.AccessTokenValidation/JwtBearer know which you scheme challenge you are trying to pass?
Multiple requirements could work, but you need to add extra requirements on the condition that you are dealing with a non-identity access token. How can you detect what type of token you are dealing with? Is it safe to just say "If no sub, this is client creds."
Should I scrap this design and force device code flow on my users? Look at az cli it magically opens a browser, and then you can start scripting away to your hearts content. IS4 supports this with ease, especially with verficationUrlComplete
I think I have a working POC, but I am far from happy with it. https://gist.github.com/VictorioBerra/8c333a228c55d86a7c15f7f300284634
It involves basically re-implementing the default scope claim requirement handler and policyservers permission requirement handler. But thats the only way to conditionally apply the requirement handlers based on the token type.
There are at least a couple of ways of how to go around your problem of implementing role based authentication:
You might have misunderstood the fact that a client can have role claims in the client_credentials flow.
You could even have sub claim if you implemented client_credentials_custom flow and essentially bind a client to a particular user account (think of this as a service account)

Manually expire JWT token from server - WEB API 2

I am working on a api server which revives requests from a mobile app. I am using JWT with ASP.Net MVC Web API 2. In this Admin gives access of various departments to mobile app users. I set these DeptIds in Claims at the time of Login. On every authorised request from app, in a custom action filter attribute I read claims to match deptId in request URL with claims. This all scenario works fine.
Now my problem is, when Admin revokes access of any particular dept from app user, how should I expire the access_token of that user so that, on Login request call, I can set new Claims. Otherwise, as Admin removes access from server but the deptId still exists in user's Claims so user still have access to that department.
One way is on every request, check in database for access but that increases overhead of server also increases response time. So I don't want to go this way.
I didn't find anything on web how to expire token in JWT. Can any one help on this?
A JWT token happens to be a kind of token that allows it to be self-contained i.e. one can validate it without consulting an external entity.
That also means that there's no external entity that will tell you that the token was revoked or expired. Expiration can only happen by some property in the JWT itself; the exp claim was standardized for that purpose: it will tell the recipient the time after which the information in it must no longer consider to be valid
Authentication and Authorization are different things.
Use JWT for Authentication but not for Authorization. I mean that using JWT you can know who the user are but don't put information about what user can do into the JWT. Check permissions for the user on the server side basing on just user's identity that you got from JWT. You may also put into JWT some information that additionally limits access rights (i.e. blacklisting; for example, social network site creates an access token for a game to access my identity and friends list but not my posts) but don't put there information that directly provides access to some features (i.e. whitelisting). In that way you can easily remove access to some features on your sever-side despite that fact that the user is already logged in with JWT.
I understand you are interested in revoking or invalidating tokens instead of expiring them.
Revoking or invalidating tokens
Unfortunately​ it's not possible to achieve it
without keeping the track of the tokens somewhere:
Issue a token and add it to a whitelist to keep the track of it.
When validating a token, check the whitelist and refuse the request if it is not whitelisted.
To revoke or invalidate a token, remove it from the whitelist.
This security schema require some trade-offs. Deal with it.
Performance considerations
Regarding your performance concerns: Bear in mind that premature optimization is the root of all evil. You shouldn't optimize until you have a performance problem and you have proven that the performance problem comes from the way you store your tokens.
You could start storing the tokens in the database and then consider a cache in memory, for example. But always be careful when fixing a problem that you currently don't have.
Token identifier
The jti claim should be used to store the token identifier on the token. When validating the token, ensure that it's valid by checking the value of the jti claim against the token identifiers you have on server side.
For the token identifier you could use a UUID.

What are the advantages to the OpenID OAuth Extension over OAuth?

Why use the proposed OpenID OAuth Extension over another OAuth-based protocol?
Discovery doesn't seem to be a feature. Although the consumer only needs a claimed identifier to start the authentication process, any authorization will still require that the consumer knows the access token URL, signature methods, and have a shared key/secret with the provider.
One benefit is that there's a specified way to ask for specific authorizations, the openid.oauth.scope argument to the authentication request. And one specific benefit for this is that authentication only - for the benefit of the consumer only, with no verifiable token - is defined for free and can be performed without worrying about keeping track of outstanding tokens or the resources they might require.
Are there examples of alternative ways in use to specify the scopes to be requested, perhaps with something in OpenID discovery? Or could this be handled effectively with some kind of REST navigation before the OAuth process, where one of several request token URLs specific to the desired scopes is discovered by interpreting hypertext starting from a well-known URL?
I am researching a delegated authentication and authorization system with several authorization scopes, where the scopes are relevant for different interactions. In other words, the consumer needs to tell the provider which scopes should be presented to the user for authorization.
The OpenID+OAuth extension really has only one significant advantage over standard OAuth:
If you need to authenticate the user and access the user's private data, and the OpenID Provider happens to also be the OAuth Service Provider (the user authenticates with the same service that holds his private data), then the extension will help the user have just one redirect to the OP+SP instead of two separate ones. For the user, this is a huge usability win -- if he happens to be authenticating with his SP.
The risks of supporting the extension is adequately supporting users whose OP and SP are not the same entity (you don't want to say you'll support the extension and then inadvertently lock out users whose OP is not also their SP).
Keep in mind what you really need to know. If you only want to access the user's private data, but don't really care who the user is that you're interacting with, use just OAuth. No reason for the user to give up his identity via OpenID if you're only downloading his photos to offer a photo printing service, for example, or if you already have a non-OpenID account for this user.