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).
Related
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.
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.
I'm creating a mobile app for customers that need to access an api that I use.
The api requires authentication and the app needs to call the api to receive some data that is specific to each individual customer(mobile app).
I just want to make sure that the right way to do this is for the mobile app to send the query to my server which will then make the authenticated api call and return the response to the mobile client?
or is it possible to have the mobile make the api calls directly, presumably using the same authorisation key?
This is primarily an opinion-based question, however I'll give it a go:
[paraphrased] Can my server act as an API proxy to make authenticated calls to another API on behalf of my unauthenticated users?
This is a common occurrence in the API world, but some things you need to consider:
It's an extra layer in between the user and the service, which adds time to the data transport. Make sure you build your proxy to be scalable or use a 3rd party service that can manage that on your behalf. Either way, don't forget to factor in cost.
Usually service providers require authentication for a reason. Are you violating any license agreements by opening up their API like this?
Is the authentication per-application, or per-user? If it's per-user (e.g. each user logs in and retrieves a unique access_token) then you're going to be making calls to the back-end API as a user instead of an application.
Is the destination API rate-limited? Instagram's API, for example, only allows 5000 requests per hour. If you have 10,000 users that use it once per hour, you'll have already hit that limit.
Are there security concerns opening up the destination API like this? Is there sensitive information that you need to protect? If so, opening it up like you do are you creating security holes?
Is it possible to have the mobile make API calls directly to the target API, presumably using the same authorization key?
Absolutely this is possible - provided that you follow the authentication flow established by the target API. You'll want to consider the same list of concerns listed above though, in addition to:
If you're using an auth flow like OAuth2, the standard dictates that each user should authenticate as themselves and make API calls using a unique access_token. Does your target API provider offer this service? If so, that's the way to go, that way if an access_token is compromised, only that user's data/account/etc. is at risk.
If you're using app-level authentication (e.g. your app's client_id and client_secret) directly in your mobile app, be warned that it can be obtained and compromised with little effort, and thus an attacker could gain access to the entire target API this way.
I have a mobile iOS application that I want to authenticate to a RESTful API.
Every user potentially has multiple devices linked to the same account.
So far I came up with the following:
Client-side
Let user login with username/password
Send username/password & unique device id to server
Get authToken from server and set it in the HTTP Authentication header for each API call
On logout, remove authToken
Server-side
API uses SSL
user has many associated devices
devices are represented by unique device id and authToken
each time the user changes password, regenerate all authTokens
if a device is removed, delete authToken for that device
Would that be a secure approach to access the API and manually add/revoke devices?
Yes, this is a fairly standard approach. Google has a document that describes this approach (a majority of the document is geared toward getting the token from the server to the client so that may not be as useful to you). And some more detailed description of bearer token authentication.
You should see if the application framework you're writing the server in already supports an authentication mechanism like OAuth, so you won't have to write your own.
Is it possible to identify (authenticate) a mobile application HTTP request ?
for example a request from a web server can by identified by the domain or IP, assuming I know from where it should come from I can accept the request or deny if it came from an unexpected origin.
doe's mobile application has some sort of unique id (that cannot be mimicked)?
If you need to make secure HTTP calls (webservice API) from a mobile app (a native compiled app), you can try the following approach:
Edit: This approach assumes that you can't rely on the user operating the app for authentication purposes (because then you could simply ask the user to type in a secure password in the app).
Assuming you are implementing the app, save some sort of secret API key in the code.
When the app makes an API call via HTTP, it will always be done using HTTPS (so everything is encrypted).
The app will send the secret API key as a URL parameter.
The server will authenticate by checking if the secret key is correct.
Sniffing the app traffic will not reveal the secret key (because of the HTTPS).
You are mostly vulnerable to someone reverse-engineering your app to discover the secret key inside. This can be made tough by using various obfuscation and anti-debugging techniques, but cannot be made truly impossible. As long as you're using a compiled language (like Objective-C, not JS for a web-app) this will already be tough without any special games. If you avoid placing your API key string as-is and compute it using some short code in the app, you've made it about 1000 times tougher to discover.
Without knowing more about your specific problem, it's hard to suggest alternate approaches. Please give more details if you are looking for something different.
There are two methods used in practice. HTTP basic authentication (not much secure for mobile apps) and OAuth2 (secured compared to HTTP basic authentication).
HTTP Basic Authentication: The process is simple for both technical writers of API services, and also developers using them:
A developer is given an API key (typically an ID and Secret). This API key usually looks something like this: 3bb743bbd45d4eb8ae31e16b9f83c9ba:ffb7d6369eb84580ad2e52ca3fc06c9d.
He is responsible for storing API key in a secure place on their server, so that no one can access it. He makes API requests to the API service by feeding the API key in the HTTP Authorization header along with the word 'Basic' (which is used by the API server to properly decode the authorization credentials). The key is also Base64 encoded.
For example key could be: 3bb743bbd45d4eb8ae31e16b9f83c9ba:ffb7d6369eb84580ad2e52ca3fc06c9d
encoded in base64: M2JiNzQzYmJkNDVkNGViOGFlMzFlMTZiOWY4M2M5YmE6ZmZiN2Q2MzY5ZWI4NDU4MGFkMmU1MmNhM2ZjMDZjOWQ=.
The API server reverses this process. When it finds the HTTP Authorization header, it will decode base64 result, read the API key ID and Secret and validate these tokens before allowing the request to be processed.
HTTP Basic Authentication is simple but for mobile apps securing the API Key is a main concern. HTTP Basic Authentication requires raw API keys to be sent over the wire for each request, thereby increasing chances of misuse in the long run.
Also it is impractical as you cannot safely embed API keys into a mobile app that is distributed to many users.
For instance, if you build a mobile app with your API keys embedded inside of it, a user could reverse engineer your app, exposing this API key, and abusing your service.
So HTTP Basic Authentication risky in open environments, like web browsers and mobile applications.
NOTE: Like all authentication protocols, HTTP Basic Authentication must be used over SSL at all times.
OAuth2 for Mobile API Security:
OAuth2 is an excellent protocol for securing API services from open devices, and provides a better way to authenticate mobile users via token authentication.
OAuth2 token authentication works from a user perspective (OAuth2 name it password grant flow):
When a user starts the mobile app he is prompted for username or email and password.
The developer sends a POST request from app to API service with the login data included (over SSL). Then validate the user credentials, and create access token for the user which expires after a certain amount of time. This access token can be stored on mobile device, treating it like an API key which allows access to API service. When the access token expires user is prompted again for login details.
OAuth2 generates access tokens that can be stored in an open environment temporarily and are secure. It is secure because the access token are generated for temporary purpose and it reduces damage potential.
The token is stored according to the mobile platform used. For Android app, access tokens can be stored in Shared Preferences and for iOS app, in the Keychain.
It depends on how you define "mobile application". Any application running on a mobile device ? Web browsing running on a mobile device ? What is a mobile device to you ?
Anyways, the general short answer, is that you can detect the device type using the User-Agent sent in the HTTP headers. All popular mobile browsers sends this. But be aware, that:
It can be spoofed (easily)
Some applications (ie iPhone or Android apps and similar) can be written in such a way, that they don't send a user agent with the HTTP requests. Best practice mandates to send the User-Agent though.
I don't know of a more reliable way to do this; and as long as stuff happens over HTTP there generally won't be any way of knowing anything about the client for certain. For mostly all the use cases, you will be alright with looking at the User-Agent.
You can buy access to User-Agent databases containing various device data, if applicable, two of such being WURFL or DeviceAtlas.