Protect my public oauth API from abuse, but allow anonymous access from my app? - api

I have a website and an API. The website allows anonymous people to browse the catalogue, but you must be logged in to post stuff.
I have built an API that exposes the same functionality. The API is used by a mobile app we are developing, but we are also going to allow other developers to use the API (i.e. it's publicly documented). The entire API is currently requires OAuth (2.0) authentication. To prevent abuse we use rate-limiting per OAuth client-id/user-id combination.
Now a new requirement for the mobile app has come down: The app should allow anonymous users to browse our catalogue. I am not sure how to implement this, without opening up our API to abuse.
Anonymous OAuth access
The first problem is allowing anonymous access. If we still want the entire API protected by OAuth then our mobile app will have to use the client-credentials grant type (posting a client-id and secret key). But we would have to store the client-id and secret in the app itself. This is not secure since it can easily be reverse engineered.
Alternatively, we could use dynamic client registration. As soon as an app is installed, it registers with an (undocumented) API to create an OAuth client for itself. Problem here is, how do I protect the client registration endpoint? A secret key again? Plus, this leads to a large amount of OAuth clients registered.
Remove OAuth from public endpoints
Alternatively, we could remove OAuth from the public endpoints all together (i.e. browsing the catalogue) and only require OAuth for posting stuff or managing an account. But how would I protect the API from abuse then? Without OAuth I cannot rate-limit based on client-id.
I am not sure that rate-limiting based on IP address would work. We expect many mobile app users and I fear that crappy (Moroccan) mobile telecom providers are NAT-ing a large amount of phone users behind just a few IP addresses. This would quickly exhaust any rate-limit that we set.
Is this correct? Or can I safely rate-limit on IP address for mobile users?
Alternative security mechanism
I could also implement a different authentication mechanism alongside OAuth. Something that allows our mobile phone app access to the API, which can distinguish (and rate-limit) different phones/users but which is safe from people just extracting a shared secret key from our mobile app binary.
Any suggestions on how to allow anonymous access to my API but still rate-limit effectively?

Since, the mobile app is installed on a device, if you configure a secret, then that secret will be common for all installations of the mobile app. Thus, derailing the purpose of a secret.
You should do dynamic registration. Here are the steps
Developer preconfigures the the following information with a trusted authority.
{
"software_id":"COMMON_VALUE_HERE",
"software_version": "OPTIONAL_BUILD_VERSION",
"client_name":"HUMAN_READABLE_CLIENT_NAME",
"client_uri":"OPTIONAL_FOR_CLIENT_CREDENTIALS",
"logo_uri":"OPTIONAL_FOR_CLIENT_CREDENTIALS",
"tos_uri":"OPTIONAL_TERMS_OF_USE"
}
The trusted authority generates a "software_statement" in exchange of the information that the developer provided. This contains the information that is constant for all installations of the native app.
After the app is installed on the user device, the app contacts the Authorization server for dynamic registration. The app posts the following to Authorization server
{
"redirect_uri" : "OPTIONAL_FOR_CLIENT_CREDENTIALS",
"scope": "SPACE SEPARATED SCOPES",
"software_statement": "MANDATORY"
}
The Authorization server verifies the information present in the "software_statement", generates and returns back a "client_id" and "client_secret" that are specific to the particular installation of software.
The client calls "POST" method on token endpoint with the newly received "client_id" and "client_secret", and receives an "access_token".
The client uses the "access_token" for accessing the "protected_resource".
The source of my answer is "oauth 2 in action" by Manning publication.

Related

How do I allow users to link with Spotify without exposing my Spotify client id & secret on the frontend?

Here's my setup. I have a NodeJS express server providing endpoints and hosting my frontend which I've built using React. I have the Spotify client id & secret stored in a .env file which the frontend references, and therefore publicly exposes.
Currently, for users to link with Spotify, the frontend can redirect to Spotify's authorize page and pass the client id and secret (and a redirect uri) in the url params. They then log in with their Spotify credentials and accept my app's terms. Then Spotify then redirects them to the provided redirect uri, which is just another page of my React app. The user's refresh token is passed as a url param for my frontend to receive. It then sends refresh token to my server using one of my endpoints and I store it in my database under their account.
This works fine, except for the fact that my app's client id and secret are publicly exposed through my frontend. I'm trying to work out a way to allow users to link with Spotify without having the frontend know this information, because if it leaks then people can make calls to Spotify's API on my behalf. But I can't seem to get around the fact that the client's browser needs to at some point have access to something like this.
const url =
'https://accounts.spotify.com/authorize?' +
querystring.stringify({
response_type: 'code',
client_id: spotify_client_id,
scope: spotify_scope,
redirect_uri: spotify_redirect_uri
})
window.location.href = url
I'm new to web development so there may be something obvious I'm neglecting. If anyone has any ideas, I'm all ears. Thanks in advance!
In this particular scenario, you’ve designed around the entirely wrong OAuth flow for the job. Client credentials-style authentication/authorization is not intended to be used in the manner you describe, for the reasons you describe. Instead, you should be using the offered authorization code with PKCE flow, which provides similar functionality for web apps, etc. without necessitating the exposure of your sensitive authentication secrets.
Spotify is pretty explicit about this in their documentation (emphasis mine):
Which OAuth flow should I use?
Choosing one flow over the rest depends on the application you are
building:
If you are developing a long-running application (e.g. web app running on the server) in which the user grants permission only once,
and the client secret can be safely stored, then the authorization
code flow is the recommended choice.
In scenarios where storing the client secret is not safe (e.g. desktop, mobile apps or JavaScript web apps running in the browser),
you can use the authorization code with PKCE, as it provides
protection against attacks where the authorization code may be
intercepted.
For some applications running on the backend, such as CLIs or daemons, the system authenticates and authorizes the app rather than a
user. For these scenarios, Client credentials is the typical choice.
This flow does not include user authorization, so only endpoints that
do not request user information (e.g. user profile data) can be
accessed.
The implicit grant has some important downsides: it returns the token
in the URL instead of a trusted channel, and does not support refresh
token. Thus, we don’t recommend using this flow.
It may go without saying, but since you’ve already elected to publicly publish your app secret, you should consider it compromised and invalidate it immediately before malicious actors are able to indeed use it to craft abusive API requests.

OAuth2.0/OIDC Public Clients: What implementation is recommended for authentication & scopes consent when there is no third-party involved?

Context
I am developing a solution with
Two clients, a mobile one and an SPA.
An authorization server under my control.
A resource server / identity provider, that provides user data and features through an API.
I am using OAuth2.0 because it can provide advantages such as allowing third-party apps to easily integrate with my Auth server / IdP, whether it be to have access to user data, or API features. It would also allow the clients to integrate with other IdPs and eventually have their data migrated over to mine.
OAuth Flow
Authentication
During the OAuth flow, there is a redirection to authenticate the user on the authorization server. At that point user enters credentials and consents to the scopes/claims clients want access to. In the case of third-party client applications I understand that:
Mobile: the latest RFCs recommend browser custom tabs for mobile apps.
SPAs: Being browser-based, here a simple redirection.
But that's the use case where it's a third-party client app delegating authentication and account management to my IdP system. This ensures the mobile application can't snoop on user's credentials (and eventually leverage sso solution of IdP so there's no need for credentials input).
In my case, I own both the client and the rest.
My first question is: Since I own the application, whether it be mobile or web, do I necessarily need to implement that redirection to a UI hosted on my IdP? Or can I have a form directly as a part of the mobile/web app and authenticate the user through REST (and then follow the rest of the OAuth flow to deliver an AccessToken + IdToken for OIDC)?
Scopes
When it's third-party client applications, I understand that we must display to the end-user the data (scopes/claims) the client wants access to. User must give an explicit consent and know what data is going to be used by the application.
But in my case, since I own the application, can't I just have a Terms & Conditions page the user approves to use the app and skip the scopes/claims approval in the OAuth flow?
In brief, what's best practice and why when there's no third-party involved?

Do I not need to secure my API endpoints (resources) with OAuth 2 access tokens?

There are multiple partied involved in OAuth2 conversation. Consider the
following diagram from the article here
Consider that I have an application that has data for restaurants and has APIs related to it. Let's call is restaurants APIs. Let us assign some role to each party in context of this example
User - our chefs, who have some recipes in restaurant
Application - Web client written in HTML5, JS, CSS that our Users use to interact with APIs
OAuth Endpoint - Google (who acts as Authorization Server)
API - My application API keeping all data for chefs
The workflow for Implicit (as per above diagram in the link) states the Application gets the access token and then the Application(browser) calls API (my application with chefs recipes) and gets the data back.
Questions
Shouldn't I secure my application endpoints or rather just believe the accesssTokens? Yes, the trust is established between Application and OAuth Endpoint (Google), but there is no trust developed API and Application by confirming the validity of accessToken with OAuth Endpoint (Google)?
If I should secure my application API endpoints, shall I have a /login endpoint for my APIs where my application accepts accessTokens, validate and create a JWT based headers for clients to use for further communication with protected resources like /recipes.
Looking forward to your ideas here.
Thanks in advance
TL;DR - don't blindly trust the access tokens. Ask Google to reveal the user/email associated with them and the client ID that was used when generating them. You can still provide a /login endpoint for scalability purposes mostly.
Let's deal with the core security first
OAuth is a delegation protocol, not an authentication protocol. To quote from the OAuth website:
The OAuth 2.0 specification defines a delegation protocol [...] OAuth is used in a wide variety of applications, including providing mechanisms for user authentication. [...] Let's say that again, to be clear:
OAuth 2.0 is not an authentication protocol.
Because it's not an authentication protocol, your app/API never learns who the user is. It just gets a token. Delegation in this context means that OAuth lets App A request access to resources in App B that belong to a User, by having the User authenticate to App B and then passing the token back to App A. In your example, it can provide your web app with access to Google resources (email, photos, etc. - depending on the required scopes) that are owned by the Users (chefs).
Note that this isn't what you are doing here, since you're accessing resources managed by your app, not by Google. In particular, as you correctly identified, the access token means nothing to your API. I could just as well give it a random string.
You might be tempted to use the following scheme:
Implement the implicit scheme as described in your question.
Have the API server validate the access token with Google, and ask Google for the name or email associated with the token. This will be the identity of the user who actually logged in to Google, and you can then decide whether or not to grant permission to that user.
The problem with this approach is that many apps use OAuth with Google, and so many apps will have Google access tokens that don't belong you app. How can you tell the difference?
You can ask Google, when you present it with the access token, to also provide you with the client ID that was provided when this token was generated (see how your diagram indicates that the client ID is sent?). Since that client ID uniquely identifies your app, then your API can tell that it's been given tokens that only came from your app. Note that this critical part of the OAuth flow is very different in mobile apps which is why the implicit flow should not be used with mobile apps (but it's fine with web apps).
Note that your client ID should be considered common knowledge (e.g. it's found in the .js files on the machines performing this flow), but it cannot be spoofed because as part of the OAuth flow, the user's browser will be redirected to a URL that is pre-configured in Google and belongs to your app. So even if a malicious app uses your client ID, Google will still send the token to your app.
Other practicalities
The above requires you to issue a call to Google on every API call, or at least cache the valid access tokens (which means you keep state, which is a bummer for scalability). If you want to avoid this, you can create a /login endpoint which generates a JWT. Note that you'll still need to validate the access tokens upon login.

Secure third-party API calls on mobile app

I have an API with the following method:
https://api.example.com/services/dosomething
I am providing this service to three different mobile apps, each one with hundreds of users. When a user logs in in the mobile app, a call to my API needs to be made.
I know that providing each one of the three mobile apps a different API Key and doing a HTTP Basic Authentication with it is not secure, since the API Key would be unsafely stored in the device an anyone can take it and make bad use of it.
The approach of OAuth2 doesn't work, since I only have information of my three customers, not their hundreds of users.
What is the best approach to secure the calls to my API on mobile?
In your case, your approach with OAuth2 is good: mobile apps (clients) receive delegation from resource owners (your users) to call protected resources on a resource server (your API).
You only have information about your clients because OAuth2 is not dedicated to authentication of your users but authorization of you clients.
The clients are identified with a client ID. In your case and if you want to know which client calls your resource server, then each client should have a dedicated client ID. You may also identify it using other information such as the IP address or a custom header in the requests it sends.
If you want to know who your users are, you should implement the OpenID Connect extension. This extension works on top of an authorization server based on OAuth2.
The authentication of the user is performed by the authorization server. An ID Token is issued with information about the user. The client (or mobile app) does not have to get or store user's credentials.
There is an excellent video where the both protocols are explained (especially from 4:44 to 11:00).

Security for "Private" REST API

I am currently developing a web application that is right now comprised of a front end which displays and interacts with the data using a REST API we have written. The only thing that will ever use the API is our front end website, and at some point a mobile app that we will develop.
I have done a lot of reading about how OAuth is the ideal mechanism for securing an API and at this point I am starting to have a good understanding of how it works.
My question is -- since I am never granting access to my API to a third-party client, is OAuth really necessary? Is there any reason it is advantageous? Furthermore, because the back end is simply the API, there is no gateway for a user to authenticate from (like if you were writing an app using the Twitter API, when a user authenticates they would be directed to the Twitter page to grant to access then redirected back to the client).
I am not really sure which direction to go in. It seems like there must be some approach halfway between http authentication and OAuth that would be appropriate for this situation but I'm just not getting it.
From my point of view, one of the scenarios that favor OAuth over other options is to work with untrusted clients, no matter if these are developed by you or a third party.
What's an untrusted client? Think from the point of who handles the credentials that grant access to your API.
For example, your web application could interact with your API in two falvors:
Your web app server side talks to your API. Your web app server is a trusted client because the credentials to access your API can only be access by whom have access to the server...You and your team. You could authenticate your web app server with a client_id and a client_secret.
You may want to make calls directly to your API from your Web app client, which runs on the end user's browser using JavaScript. The end user's browser is an untrusted client. If you were to deliver the credentials to your API down to the browser, anyone could check the JavaScript code and steal your credentials.
A third party Native App is also untrusted. A malicious developer that uses your API could save the credentials of and end user of your platform.
Your Native App is a trusted client and could manage the authentication with a simple username , password and a client id identifying your App.
How can OAuth help? OAuth Authorization code and Implicit grants can help you with this issue. These flows only work with clients that support a redirect, like a browser. And let you authenticate an untrusted client and a user against your Authorization Server to gain access to your Resource Server, your API, without exposing the credentials. Take a look at the RFC to see how it is done.
The good thing of OAuth is that it not only supports these redirect based authentication flows, but it also supports client credentials grant and user credentials grant. So an OAuth Authorization Server would cover all cases.
OAuth 2.0 originally seems like a PITA if you think about having to build a lot of it yourself, but most languages have some really solid OAuth 2.0 setups which you can just bolt in with varying amounts of fiddling. If you're using a framework like Laravel or RoR then it's barely any work.
PHP: http://oauth2.thephpleague.com/
Ruby (Rails or Grape): https://github.com/doorkeeper-gem/doorkeeper
If you don't want to redirect users as suggested in your post then ignore other comments and answers that talk about two legged flows. You can use the client_credentials grant type to have apps just provide their client id and secret in return for an access token, which is nice and easy.
I would ask how private are we talking, because if the only systems talking to it are within the backend and have no interaction with the outside world you could probably leave it wide open and just rely on the network to keep it safe (VPN/Firewall).
But if it's private in the sense of "our iPhone app uses it" then you definitely want to go with OAuth 2.0, or something like it.
2 legged OAuth is probably what you want to use. It's basically hashing a shared key, but you have the advantage of not having to write the code yourself.
Here's a related question: Two-legged OAuth - looking for information
You should use Oauth for mobile device to API layer communication.
However, there is no benefit of Oauth in this web UI layer to middle-layer access (machine to machine).
On the other hand there are some potential issues
Managing the access token expiry becomes a pain. Consider that your UI has to cache the access token across multiple nodes in a cluster. Refresh it when expired, and the fact that UI layer is negotiating security with backend will just take extra time once in a while.
In two legged Oauth (OAuth Client Credential as in v2.0) does not support any encryption. So you still need to send key and secret both to the server for getting an access token.
Backend has to implement issuing access token, refresh token, validating access token etc, without any significant benefit