API Keys vs HTTP Authentication vs OAuth in a RESTful API - security

I'm working on building a RESTful API for one of the applications I maintain. We're currently looking to build various things into it that require more controlled access and security. While researching how to go about securing the API, I found a few different opinions on what form to use. I've seen some resources say HTTP-Auth is the way to go, while others prefer API keys, and even others (including the questions I found here on SO) swear by OAuth.
Then, of course, the ones that prefer, say, API keys, say that OAuth is designed for applications getting access on behalf of a user (as I understand it, such as signing into a non-Facebook site using your Facebook account), and not for a user directly accessing resources on a site they've specifically signed up for (such as the official Twitter client accessing the Twitter servers). However, the recommendations for OAuth seem to be even for the most basic of authentication needs.
My question, then, is - assuming it's all done over HTTPS, what are some of the practical differences between the three? When should one be considered over the others?

It depends on your needs. Do you need:
Identity – who claims to be making an API request?
Authentication – are they really who they say they are?
Authorization – are they allowed to do what they are trying to do?
or all three?
If you just need to identify the caller to keep track of volume or number of API Calls, use a simple API Key. Bear in mind that if the user you have issued the API key shares it with someone else, they will be able to call your API as well.
But, if you need Authorization as well, that is you need to provide access only to certain resources based on the caller of the API, then use oAuth.
Here's a good description: http://www.srimax.com/index.php/do-you-need-api-keys-api-identity-vs-authorization/

API Keys or even Tokens fall into the category of direct Authentication and Authorization mechanisms, as they grant access to exposed resources of the REST APIs. Such direct mechanisms can be used in delegation uses cases.
In order to get access to a resource or a set of resources exposed by REST endpoints, it is needed to check the requestor privileges according to its identity. First step of the workflow is then verifying the identity by authenticating the request; successive step is checking the identity against a set of defined rules to authorizing the level of access (i.e. read, write or read/write). Once the said steps are accomplished, a typical further concern is the allowed rate of request, meaning how many requests per second the requestor is allowed to perform towards the given resource(s).
OAuth (Open Authorization) is a standard protocol for delegated access, often used by major Internet Companies to grant access without providing the password. As clear, OAuth is protocol which fulfils the above mentioned concerns: Authentication and Authorization by providing secure delegated access to server resources on behalf of the resource owner. It is based on access Tokens mechanism which allow to the 3rd party to get access to the resource managed by the server on behalf of the resource owner. For example, ServiceX wants to access John Smith's Google Account on behalf of John, once John has authorized the delegation; ServiceX will be then issued a time-based Token to access the Google Account details, very likely in read access only.
The concept of API Key is very similar to OAuth Token described above. The major difference consists in the absence of delegation: the User directly requests the Key to the service provider for successive programmatic interactions. The case of API Key is time based as well: the Key as the OAuth Token is subject to a time lease, or expiration period.
As additional aspect, the Key as well as the Token may be subject to rate limiting by service contract, i.e. only a given number of requests per second can be served.
To recap, in reality there is no real difference between traditional Authentication and Authorization mechanisms and Key/Token-based versions. The paradigm is slightly different though: instead of keep reusing credentials at each and every interaction between client and server, a support Key/Token is used which makes the overall interaction experience smoother and likely more secure (often, following the JWT standard, Keys and Tokens are digitally signed by the server to avoid crafting).
Direct Authentication and Authorization: Key-based protocols as a variant of the traditional credentials-based versions.
Delegated Authentication and Authorization: like OAuth-based protocols, which in turn uses Tokens, again as a variant of credential-based versions (overall goal is not disclosing the password to any 3rd party).
Both categories use a traditional identity verification workflow for the very first interaction with the server owning the interested resource(s).

Related

Is it possible to utilise Open ID Connect flows for authentication but then have another source of authorization rules?

My situation is this. I have a legacy Angular application which calls a Node API server. This Node server currently exposes a /login endpoint to which I pass a user/pwd from my Angular SPA. The Node server queries a local Active Directory instance (not ADFS) and if the user authenticates, it uses roles and privileges stored on the application database (not AD) to build a jwt containing this user's claims. The Angular application (there are actually 2) can then use the token contents to suppress menu options/views based on a user's permissions. On calling the API the right to use that endpoint is also evaluated against the passed in token.
We are now looking at moving our source of authentication to an oAuth2.0 provider such that customers can use their own ADFS or other identity provider. They will however need to retain control of authorization rules within my application itself, as administrators do not typically have access to Active Directory to maintain user rights therein.
I can't seem to find an OIDC pattern/workflow that addresses this use case. I was wondering if I could invoke the /authorize endpoint from my clients, but then pass the returned code into my existing Node server to invoke the /token endpoint. If that call was successful within Node then I thought I could keep building my custom JWT as I am now using a mix of information from my oAuth2 token/userinfo and the application database. I'm happy for my existing mechanisms to take care of token refreshes and revoking.
I think I'm making things harder by wanting to know my specific application claims within my client applications so that I can hide menu options. If it were just a case of protecting the API when called I'm guessing I could just do a lookup of permissions by sub every time a protected API was called.
I'm spooked that I can't find any posts of anyone doing anything similar. Am I missing the point of OIDC(to which I am very new!).
Thanks in advance...
Good question, because pretty much all real world authorization is based on domain specific claims, and this is often not explained well. The following notes describe the main behaviors to aim for, regardless of your provider. The Curity articles on scopes and claims provide further background on designing your authorization.
CONFIDENTIAL TOKENS
UIs can read claims from ID tokens, but should not read access tokens. Also, tokens returned to UIs should not contain sensitive data such as names, emails. There are two ways to keep tokens confidential:
The ID token should be a JWT with only a subject claim
The access token should be a JWT with only a subject claim, or should be an opaque token that is introspected
GETTING DOMAIN SPECIFIC CLAIMS IN UIs
How does a UI get the domain specific data it needs? The logical answer here is to send the access token to an API and get back one or both of these types of information:
Identity information from the token
Domain specific data that the API looks up
GETTING DOMAIN SPECIFIC CLAIMS IN APIs
How does an API get the domain specific data it needs from a JWT containing only a UUID subject claim? There are two options here:
The Authorization Server (AS) reaches out to domain specific data at the time of token issuance, to include custom claims in access tokens. The AS then stores the JWT and returns an opaque access token to the UI.
The API looks up domain specific claims when an access token is first received, and forms a Claims Principal consisting of both identity data and domain specific data. See my Node.js API code for an example.
MAPPING IDENTITY DATA TO BUSINESS DATA
At Curity we have a recent article on this topic that may also be useful to you for your migration. This will help you to design tokens and plan end-to-end flows so that the correct claims are made available to your APIs and UIs.
EXTERNAL IDENTITY PROVIDERS
These do not affect the architecture at all. Your UIs always redirect to the AS using OIDC, and the AS manages connections to the IDPs. The tokens issued to your applications are fully determined by the AS, regardless of whether the IDP used SAML etc.
You'll only get authentication from your OAuth provider. You'll have to manage authorization yourself. You won't be able to rely on OIDC in the SAML response or userinfo unless you can hook into the authentication process to inject the values you need. (AWS has a pre-token-gen hook that you can add custom claims to your SAML response.)
If I understand your current process correctly, you'll have to move the data you get from /userinfo to your application's database and provide a way for admins to manage those permissions.
I'm not sure this answer gives you enough information to figure out how to accomplish what you want. If you could let us know what frameworks and infrastructure you use, we might be able to point you to some specific tools that can help.

AzureAD: Using long-lived refresh tokens for external API "system" consumers?

I'm developing a bunch of APIs that will have both internal and external (to the company) consumers. I'm using AzureAD for authentication. Whilst these consumers will be integrations written in code, I don't want to have to create and manage dedicated "app registrations" for each client/consumer. I also want to be able to use roles for more granular permissions.
It feels like a long-lived refresh token is the best option for this, and I've written a working proof-of-concept for this, which meets the requirements perfectly.
Given this is security though - I wanted to ask if I'm doing anything stupid or wrong.
First question - is it okay to treat a refresh token as a long-lived secret that consumers can store in their secure config, then their systems programmatically use that to query an access token to use against our APIs?
If this is okay - my second question is regarding the client id and secret. Because the implicit flow doesn't support refresh tokens, I'm using the authorisation code-flow. For this, it looks like I have to pass the client-id and client-secret as well as the authorisation code or refresh token to AzureAD. This means that I need to create a dedicated "auth api" that the consumers call to request these tokens. This auth api literally just then makes a downstream call to AzureAD passing the clientid and secret (which the consumer obviously doesn't know about). It feels like if the implicit flow supported refresh tokens I wouldn't have to implement this "auth API" at all. But because I have to use the authorisation code flow - it's forcing me to implement a proxy "auth api" for all token requests to go through. Am I missing something - or is this the way I should be doing it? It's fine if so - as this is what my PoC is doing, and it's working. But again, just wanted a sanity check on this with it being security related.
Ps. I know Azure API Management gives a lot of this functionality - but for reasons out of scope of this question, this isn't a good fit for us.
Update
To add another couple of reasons why this method fits my use-case really well...
A lot of internal developers will also be using these APIs (internal to the company). They already have AzureAd accounts anyway. So this then becomes super-simple to manage - we just have a bunch of security groups with certain roles in the app registration, and we can just add devs to those groups. And they don't need to know the client id / secret - they just use their own user account.
The APIs have Swagger UIs. Using users instead of clientid/secret - means developers can use the Swagger UIs with single sign on.
WEB CLIENTS
So a web app is used by developers to sign in via their Azure AD account. Authorization Code Flow is fine, after which each user will get access tokens and refresh tokens for calling APIs. Tokens will include the user's role and APIs can use them for authorization.
EXTERNAL API CLIENTS
These might be B2B clients and therefore use the Client Credentials Flow. Tokens issued to these clients would then have no user context.
INTERNAL API CLIENTS
It is a little unusual for a developer to login to a web client and then take tokens issued and use them in other apps. This is partly about reliability and partly because different apps generally access different areas of data. See this scopes article for details on designing how components call each other.
REFRESH TOKENS
A refresh token is something that will expire so you need a plan for this. Avoid using them in static configuration. Consumers need to handle refresh token expiry in order for their app to be reliable.
CODED INTEGRATIONS
Are these web clients or APIs, and how many distinct apps are there? It feels like combining these into one or a few client registrations is the right option. A common setup might work like this:
All developers might share the same registration
All web clients use the Authorization Code Flow - and you Auth API
API clients forward tokens to other APIs, to maintain user context

OAuth authentication client side security issues

I understand the security issues around attempting to use OAuth for authentication from a provider's point of view. However I've been asked to provide users the facility to log on to a new web application using OAuth and obtain their basic identity info from the likes of Google and Twitter, from which a new user account within the client application will be created. Additionally users will be able to regster/login directly via user/passwords for anyone not wishing to use third party accounts.
We do not require any access to the user's details/info or providers APIs, just their basic identity when they first logon, and of course allow them to login via the provider in the future. Not exactly the use case OAuth is intended for, OpenId would have been preferred, but OAuth has been specified and without valid concerns would need to be adhered to.
My question is how safe is it to assume that the user has correctly authenticated themselves with the relevant provider. If I trust say Google to perform adequate authentication and I obtain an access token and their identity, presumably I can consider that a legitimate user? There are obviously issues if some one has access to the resource owners machine and saved passwords in the browser but that issue is present for those users who elect to register directly.
Presumably it possible to fake an access token, e.g. man in the middle pretending to be google? A MITM could fake an access token and supply identity details that matched a registered user's google id? I don't see anything for a client to know that the information definitely came from the provider. Obviously this problem is not unique to OAuth.
Are there another ways someone could illegitimately access an account that used OAuth to authenticate themselves.
OAuth allows that an application to access a specific user resource (that has been provided permission by the user) and it cannot go outside that scope. I have not seen the documentation that refers to creating a new user using OAuth based application.
That being said:
We do not require any access to the user's details/info or providers
APIs, just their basic identity when they first logon
This violates OAuth authorization process. The Service Provider does the authentication and provides the relevant tokens (based on the success of the authentication). This is to ensure that there are no 3rd party authentication done during the OAuth authentication process.
My question is how safe is it to assume that the user has correctly
authenticated themselves with the relevant provider.
This all depends on the service provider itself. To conform to OAuth protocol, one of the requirement is that user authentication must be done in a secured transport layer with a digital certificate (for HTTP, it must be done in HTTPS). OAuth consumer don't have any reference to the authentication process. Also the authentication process basically asks the user if the consumer can access the resource of the specific user (and not anyone else, since he doesn't have authorization to it).
Is it possible to fake an access token, e.g. man in the middle
pretending to be google?
Spoofing a Service Provider IS possible but it'll be tedious. For one, you will have to create a whole OAuth handshake process, create the exact API as the service provider, also setup an environment that is secured (as OAuth recommends). The only thing the spoofing service provider can obtain is the client credentials. If it has its user credentials, there is no need to use the application as there is no way of providing a user credentials using an application to do malicious damage.
Secondly, access tokens do expire so even if you spoof and retrieve an access token, the original application owner can ask for the service provider to block the application and the access token can be useless.
A man in the middle attack won't be possible. You will have to replicate the service provider in a sense that the end user won't be able to distinguish between the original and the spoofing service provider in order to capture all relevant credentials (from both the application and end user).
Sadly saying, the scenario from your last sentence is the truth.
But you should realise that the security is a huge and complex issue, especially in client side. It's not happen just in a single point but many points through the whole internet access life cycle. The scenario you given is not what OAuth try to solve.

OAuth for Server to Server API Security

So the past few days I have scoured the internet for API security 'best practises' or techniques, specifically for APIs that are accessed directry FROM a server TO a server (server-to-server). There seems to be many varied opinions, and it's hard to consolidate them into a workable idea.
According to many, OAuth is the way to go. Depending on whether one wishes to not use a secure socket protocol, the choice is either OAuth 1.0A or OAuth 2.0, respectively.
Regarding OAuth, my understanding is that OAuth 1.0A main concern is the digital signage of requests, whereas OAuth 2.0 relies on the underlying HTTPS to guarantee integrity. So am I safe to make the following assumption?
Assumption: If using HTTPS, one does not need to use HMAC or any form of digital signature to prevent replay attacks, man in the middle attacks and to maintain integrity.
This still leaves authorization, which OAuth manages via an exchanged token. But why is it so complex? Can I, for example, give all the servers (private consumers) globally unique usernames and secrets, such that each 'request' is 'signed' with some hash of the secret, username and request parameters?
This, as far as I can tell, implies authorization and authentication. Authentication is managed by the confirmation of the hash, and authorization is prohibited because, critically, every server has the same privileges to their own resources.
As such, what's the best approach when designing an API strictly for server-to-server (or "2-legged") communication? Is it safe to simply use HTTPS, and then sign each request with a personalized hash, implying authentication, authorization and also not requiring the need to maintain state/sessions.
I can understand that conformity to a standard is a benefit to developers writing code to consume the service, and the web culture in general, so adherance to some 'subset' of OAuth sounds appealing; I am just not sure if it's required here.
Assume you have system S1 that already has a trust relationship with system S2. What OAuth does is to provide a mechanism so that S1 can give S3 access to S2. That is, S3 can be given permission to act on S2, using some part of the permissions of S1. It does this in a way that S1 has control of.
Q: "Can I, for example, give all the servers (private consumers) globally unique usernames and secrets"
A: Of course you can do this. If you have username and unique password with every system you want to talk to, then you have no need of OpenID or OAuth. But this becomes very hard to manage. OAuth allows you to have one secret on one system, and authorize any number of other systems based on the one secret. That is the only reason it exists.
If you look at what OAuth does, is that it basically makes a new unique shared secret (called a token, but you can also call it a password if you like) for each kind of access to be given out. That unique secret is generated by S2, but passed from S1 to S3, and can be used as a password by S3 for accessing S2. It is S2 that is "controlling" the access. The only thing that OAuth does is get the token to S3. This eliminates the need to set up a password, and manually carry it between the systems.
When you talk about a "two legged" communications, the question is: how did the shared secret get set up between them? If you manually (i.e. physically carried) and set up both systems with password, then you have no need for OAuth. But that is a lot of trouble if you have a lot of systems. N systems would need (N*(N-1)/2) passwords.
Normally what you want to do, is to have one server act as an "authentication server" and every server has a trust relationship to that. Then, you use OAuth to authorize any interactions between any two other servers. That is what the complexity is all about.
Once you have the basic trust relationship between servers, you can on top of that sign requests or sign responses (for non-repudiation purposes).
When designing a service, you need to think about ways that access might be given out. For example, do you want time-limited access that would be good for only 7 days? Would you want to make "read-only" access available? This will give S1 options on the kinds of access to S2 that it gives to S3.
Let me illustrate with a specific example: Snow is good, and you would like to go skiing. The ski area is open, but all your money is in the bank. What you want to do, is to authorize the ski area to withdraw funds from your bank account. You don't want to give all your money to the ski area. You don't trust them with your complete password. So instead, you first contact the bank, and arrange for a "permission" to withdraw a specific amount of money. This is represented by a token. You then pass that token to the ski area. Using that token, the ski area is able to withdraw the specified amount of funds. The is always responsible for guarding your funds, and it is the bank that defines the kinds of transactions you might be able to set up permissions on. OAuth is just a standard way to pass the token around, securely.
What you've described as solution called "using client certificates for HTTPS communication" or "mutual SSL" - server presents its certificate with domain and client presents certificate somehow identifying itself. Works well for server-to-server cases.
This approach indeed allows to authenticate servers/users in secure and standard way. Your server that receives incoming requests will be able to make authorization decisions based on certificate presented by caller. Calling servers will need to either register they own certificates with your service or obtain your predefined certificates to call your service.
This approach works for cases where you can properly control distribution of client certificates or server accepts certificates obtained in some external way. If you control both ends of communication (i.e. securing traffic between components of your own multi-tiered system) than this approach is one of simplest.

Application token/secrets when creating an OAuth API

Background: I am using node.js and express to create an API. I have implemented OAuth in my API server in a standard consumer/user key/secret fashion (the same way Twitter, Facebook, etc. do). I expect 3rd parties to connect to my API, again in the same manner as these common APIs.
Normally, a client would connect with an application token/secret (eg, you create a Facebook app as a Facebook developer and these are given to you). However there are times when the client cannot provide a secret for the application because the code is implemented in an insecure fashion. Specifically, I am referring to Javascript libraries. Eg, developers do not want to expose their application secret in Javascript code because it is plaintext and could be read by malicious users.
I've noticed that Facebook avoided this problem. The developer needs to provide only an application token (not secret) to the Javascript library. I do not understand how to provide a similar option for my API without fundamentally making my library insecure. Namely, if requests are being made by a Javascript client library to an API without providing a well-secured token/secret, how are those requests authenticated by the OAuth API?
Intellectually, the best solution I could think of would to have some sort of token handoff between the Javascript client library and the API server via a HTTPS connection, in order to return a secret for the library to use. I'm not quite sure how I'd secure this handoff to prevent spoofs, though.
In most cases it is better to follow the standards than to implement some custom way. OAuth2 specifies 4 methods in the latest draft (28) to do the Authorization Grant flow. The implicit flow is the one you saw on Facebook.
As the standard says for that:
When issuing an access token during the implicit grant flow, the authorization server does not authenticate the client. In some cases, the client identity can be verified via the redirection URI used to deliver the access token to the client. The access token may be exposed to the resource owner or other applications with access to the resource owner's user-agent.
Implicit grants improve the responsiveness and efficiency of some clients (such as a client implemented as an in-browser application) since it reduces the number of round trips required to obtain an access token. However, this convenience should be weighed against the security implications of using implicit grants, especially when the authorization code grant type is available.
it has some security drawbacks.
But as far as I can see, the other methods don't work for you, as they are exposing secrets to either the client (third-party website owner) or the resource owner (user), so you should stay with this.

Resources