I am exploring possible solutions for creating something like "API Keys" to consume my API. The goal is to allow for users to generate one or many "API Keys" from the web app and use the static generated key from the CLI app.
The web app and the client app are already using standard OIDC with JWT tokens for authentication and authorization using RBAC (role-based access control). The CLI app can already authenticate the user through the standard browser flow (redirects the user to the browser to authenticate and exchange the token back to the client).
The "API Keys" solution I am trying to achieve should have some fine-grained options where it won't authenticate as the user, but will authorize the client on behalf of the user (something like the GitHub Personal Access Token).
To me it seems like a "solved problem" as multiple services provide this kind of feature and my goal is to do it the most standard way possible using the Oauth2/OIDC protocols but I can't find details on what parts of the protocols should be used.
Can anybody provide any guidance on how it is supposed to be done using the Oauth2/OIDC entities?
Can I achieve it by only using Role-based access control or do I need Resource-based access control?
It went through the path of creating a new client for each "API Key" created, but it didn't feel right to create so many clients in the realm.
Any guidance or links to any materials are appreciated.
Can anybody provide any guidance on how it is supposed to be done
using the Oauth2/OIDC entities?
OIDC is based on OAUth 2.0 so after user login you have id tokens, access token and refresh token on the backend side. To generate new access token without asking user for authentication data you should use refresh token: https://oauth.net/2/refresh-tokens/
Can I achieve it by only using Role-based access control or do I need
Resource-based access control?
resource-based access control is more flexible solution here, but if you business requirement is not complex, then role based might be enough.
It went through the path of creating a new client for each "API Key"
created, but it didn't feel right to create so many clients in the
realm.
It is one application so you should use one client with specific configuration for access token and roles/permissions for users.
Update:
We can use GitHub as an example:
User is authenticated during login
for OIDC code is exchanged for id token, access token and refresh token
session for user is set for web browser
User can request access token
in GitHub authenticated user can request github.com/settings/personal-access-tokens/new endpoint
request is accepted, because user is authenticated based on session
backend service responsible for returning access token can obtain new access token using refresh token from point 1.
access token is returned to GitHub user
To call your API in an OAuth way, CLI users must authenticate periodically. Resulting access tokens can be long lived, as for GitHub keys, if you judge that secure enough. The access token returned can be used exactly like an API key. There may be a little friction here between usability and security.
CONSOLE FLOW
The classic flow for a console app is to use the Native Apps Desktop Flow from RFC8252. This involves the user interactively signing in using the code flow, then receiving the response on a loopback URL. It is an interactive experience, but should only be required occasionally, as for GitHub tokens.
API KEYS
The access token returned is sent in the authorization header and you can use it as an API key. Access tokens can use a reference token format. to make them shorter and confidential, to prevent information disclosure. These will be more natural in a CLI.
API AUTHORIZATION
When your API is called, it must receive access tokens containing scopes and claims, to identify the user. This will enable you to authorize correctly and lock down permissions.
{
sub: 586368,
scope: repos_write,
topic: mobile,
subscription_level: silver
exp: ?
}
TOKEN REFRESH
Sometimes CLI access tokens are long lived, for convenience. A more secure option is for the CLI to use token refresh. It can then store a refresh token in OS secure storage, then renew access tokens seamlessly. My blog post has some screenshots on how this looks, and a desktop app that does not require login upon restart. The CLI needs to deal with expired access tokens and handle 401 responses.
DYNAMIC CLIENT REGISTRATION
Some developer portal scenarios use DCR. It is another option in your security toolbox. It could potentially enable a silent client per CLI user:
User runs a standard authentication flow with a DCR scope
This returns an access token that enables client registration
The resulting token is used to register a new client
This could potentially be a client ID and client secret used in a CLI
Afterwards, the user and client are bound together. Probably not immediately relevant, but worth knowing about.
I have been using JWT to authenticate the users for the HTTP endpoints in my ASP.NET Core 2.1 API project. I have configured the authentication service and everything is going on well.
while generating the token, I usually set the expiry to 24 hours. My problem is, what if the user is blocked by the admin after issuing the token. Now that the token is issued the authentication middleware will simply authenticate the request.
So, I thought I need to intercept every request to make a backend call to know whether the user is blocked or not. I can do this at every endpoint level, but it is not so efficient I think.
What are the optimal solutions for this issue, which is quite common? Are there better ways to solve it than what I thought?
When you choose to use a JWT then accept the nature of the JWT. This means that the only way to have 'real-time' information is to expire the token when the information becomes obsolete. Set the lifetime of the access token to a small window, like less than five minutes. This way you know the information is always valid and you don't have to change anything about the current handling. This is 'almost real-time', as the changes become effective within five minutes.
The advantage of a short lifetime is that this also increases the security of your website. When the token is compromised, it can only be used for a short time.
You'll have to add support for a refresh token, because you don't want the user to login every five minutes. So when the access token expires use a refresh token to request a new access token. This will only work for apps that can keep a secret. Because the refresh token is very powerful and you don't want it to fall into the wrong hands. You can use one-time only refresh tokens to limit the risks and add strategies to detect different behaviour. For more details read my answer here.
You can also choose to remove authorization claims from the JWT and move authorization to your middleware, where you can real-time check the permissions of the user. In that case the JWT only includes the user claims that identify and model the user. Claims that are not likely to change very often. As a result the access token doesn't have to be short-lived, but for security reasons I think this is still advisable.
The minimal requirement is a sub or userid claim. This is enough to identify the user and grant the user access to the website.
I think the Policy Server is a good example of a possible middleware authorization implementation. Here the middleware reads permissions from a json file and adds permissions as claims to the identity. Where policies decide what the user is allowed to do. Also implement resource-based authorization.
An alternative is to use reference tokens, as implemented by IdentityServer. IdentityServer stores the contents of the token in a data store and will only issue a unique identifier for this token back to the client. The API receiving this reference must then open a back-channel communication to IdentityServer to validate the token.
The advantage here is that you can revoke the reference token at any time, using the revocation endpoint.
I'm trying to wrap my head around a specific proprietary authentication flow used by one of our customers, and how to implement it in IdentityServer4.
We're developing an SPA with some microservices as backend and do all our authentication/authorization with IdentityServer4. The standard workflow for the SPA is (as expected, I guess) the implicit flow using oidc-client-js (for now).
Now the problem: one of our customers has something like a homebrew SSO solution dating way back. Users basically authenticate at a central portal and get a link to the application with a token attached. This token is valid for a few minutes and contains the temporary user credentials, I need to somehow authenticate at our IdentityServer.
My first attempt was the client credentials flow. Doesn't work, as the client cannot refresh its access token later, once the initial credential token ran out (the client does not and cannot have access to permanent credentials.) My current approach would be to kind of "hijack" the implicit flow, by authenticating with the given temporary credentials and from there on out use the normal refresh cycle without further need for any credentials.
Is this a valid approach or am I completely on the wrong track? If it's valid: how do I get IdentityServer4 to do my bidding? I cannot use IResourceOwnerPasswordValidator, because that would require the client credentials flow (I think?). Is an IExtensionGrantValidator the way to go? (If so: any ideas, how to convince oidc-client-js to use a custom grant?)
Thanks for your help.
Regards,
Markus
I have built a Web API and now I am trying to determine the best approach to secure it.
I would like to use tokens along with credentials and thus, once the user is validated, on future requests a token can be passed with the http request. This API will always be called by one particular account and the username/password will always remain the same.
I am working with an already existing site backend, which has its own login implemented and stores user data. So I would like to stay away from creating new database tables to store user records. For that reason, I think implementing .Net Identity is maybe a overkill.
One of the options I am thinking of is grabbing the credentials from the http request and attempting the SQL connection with it. If the connection passes, then the user is legit. If it does not, it means I have to return access denied. Is this a good way of going about it? If yes, what can I use for token generation and validation?
Check out this guide which is specific for Oauth tokens with .NET:
OAuth with JSON Web Tokens In .NET
Also, make sure to follow the guideliness, because tokens must expire and be renewed after a while, for security reasons. You shoudn't use a permanent token, of course.
I have a question regarding how I should architecture a REST API using access token and API keys.
I have an API that needs authentication. I want to enable two use cases:
The user logs into the interface using OAuth2 (password grant), and is granted a temporary access token. This token is used to authenticate the user. Therefore, the UI, that itself using the API, can fetch data and display it.
I also want the user to have an API key to do the same calls, but in its application. Obviously, contrary to the access token, I want the API key to be long lived. Also, contrary to the access token that is tied to a given user (if we introduce a team mechanism, each user will have different access token, although they access the same resources), the API key should be unique to the project.
While similar, I'm not sure about how should I architecture that. I think that, internally, both API keys and access tokens should be stored in the same table, but API keys having no expiration time. Am I right?
One thing I'm not sure also is the concept of client. It seems that in the spec, the client is more like an external application. However may I actually use this concept here?
For instance, each "project" is actually a different client (although the client here is the same application, not an application created by a third-party developer).
Therefore, if user A creates an account on the system, a client A will be automatically created, with an access token tied to the client A, with a long-lived access token (aka API key). This can be used to perform API calls directly on his code, for instance.
Then, if user A logs into the dashboard, a temporary access token will be created, but this time with no application, but tied to the user, with a short life.
Does this sound sane? Have anyone already implemented such a thing?
Thanks!
I think you should not consider the "API keys" a substitute of the access token.
You will have to use an access token anyway to bear the authentication between requests, so what you're actually modelling with your "API keys" is not a replacement of the usual bearer token, but rather a different client that provides other grant types to request a token with.
The flow I'd personally implement is the following:
The user authenticates with the password grant type with a common client for every user (i.e. your "web app" client, which is public, i.e. it doesn't have a client_secret).
The user can then create its own client. As per OAuth2 specs, these are not public, so they will consists of a client_id and a client_secret. These are what you call "API keys".
A user will then be able to request an access token via their client, with any given grant type you want to support (e.g. direct client credentials, authorization code, implicit, third parties, etc.). You will have to stress quite a bit about the due safety practices on how to handle the client credentials.
Obviously, you will have to implement your OAuth2 server in such a way that clients can belong specific users, and have different acceptable grant types (i.e. you may not want to allow the password grant usage with a user client, while you may want to disallow any grant type other than the password one for your web app client).
You will then be able to define tokens TTLs, or lack thereof, on a per client or per grant type basis (e.g. access token requested via password grant, only usable by web app client, will have a short TTL, while authorization code grant will provide long lived tokens).
I would advise against complete lack of TTL, though, and rather use the refresh_token grant type to renew expired access tokens.
Furthermore, you'll probably have to define an authorization system of some some sort (ACL, RBAC, whatever), to define which client can do what. This means each access token should contain a reference to the client used for its creation.
So, to sum it up, here are the relations:
User has a Client.
Client has a User.
Client has many Token.
Token has a Client.
Token has a User.
YMMV on bidirectionals.
You should be able to implement everything I described with the most common OAuth2 servers implementations of any given platform.
TL;DR: "API keys" are actually OAuth2 clients.
I wrote a post about the way to use access tokens for RESTful applications: https://templth.wordpress.com/2015/01/05/implementing-authentication-with-tokens-for-restful-applications/. Perhaps can this give some hints.
To answer your questions, I think that we need to have something homogeneous. I mean all your authentication mechanisms should be based on access tokens. Your API keys would allow you to get an access token that would be actually used for authentication.
As far as I understand, you have two kinds of users of your applications:
End-users using the Web UI (login with password through OAuth2)
Applications (login with API keys)
So I would implement these two kinds of users and make them the ability to get access tokens. Access tokens will be used in both cases to access the RESTful services.
In addition, I think that this answer can give you some other hints: Securing my REST API with OAuth while still allowing authentication via third party OAuth providers (using DotNetOpenAuth).
Hope it answers your question.
Thierry
Thank you for your answer.
I'm actually quite experience with OAuth2 itself, my question was more targeted to API keys. I like the idea of an API key exchanging an access token but I think that does not work. The API key is fixed and does not change, while the access token can expires.
The question is: how the app can know if this is an access token or API keys. I mean, ok, let's say that in my database, each user has an "api_key" column in their database.
Contrary to an access token, the api_key does not expires (although the user can eventually rotate it). What I want, as I told, is homogeneous handling of authentication.
Case 1: my own web app do API calls
The workflow is as follow, using OAuth2:
User enters his mail/password.
Authorization server returns a temporary access token (eg.: "abc").
In the web app, all API calls are done using this token. For instance: "/payments/1" with Authorization header: "Bearer abc".
Nice and simple.
Case 2: the user has an API key, that does not expire and can be used privately in their own app
Obviously, the authorization mechanism must stay the same. So:
User goes into his account, and read that his API key is "def".
In their server code, they can do the same call, with same authentication mechanism. So he can call "/payments/1" with Authorization: "Bearer def".
And it must work. As you can see, nothing has changed in both examples. They access the same resource, same authorization mechanism... but in one case we have an access token and in other case we have an API key. And I have no idea how I should implement that both from a database point of view and in the authorization code.
One potential idea I had is using different auth mechanism. For OAuth, it would be "Authorization: Bearer accessToken", while for API it would be a Basic authentication: "Authorization: Basic apiKey".
Does this sound good?