Context
I'm developing togther with my dev team a mobile app in a client-server architecture, since there will be a webclient too, allowing some users (admins) to perform certain operations from the browser.
The REST Api currently authenticates users by returning access and refresh tokens in form of JWTs. Both local (username/password) and OAuth2.0 (only Google at the moment) flows are available, as I provide the user with these two different options for authenticating.
Problem
The flows that follow are working just fine when the API is called from the webclient, but now that we've started developing the mobile app a big question arised: **how do we keep the user authenticated on the mobile app even after the refresh token expires?**
All the famous apps out there do not prompt the user to authenticate let's say weekly or worst daily, but still I'm sure their authentication practices are (almost) flawless.
Tried paths
I've read many blog posts and articles, together with some StackExchange Q&As as reported below, but the right way to approach authentication and access persistence on mobile is still unclear.
Should I create a specific endpoint (or many) to provide non-expiring tokens only when the User-Agent header tells the API is being called by a mobile device?
As mentioned in JWT (JSON Web Token) automatic prolongation of expiration Auth0 abandoned JWT for mobile in favor of random generated strings. What implementations are available in this case? Should I use this string as a never-ending id of the authenticated device and approve all API calls that have it attached?
In the OAuth case, should I perform (I don't know how) silent calls to the OAuth provider to get back a new idToken and then request new tokens to my own API with it?
In the local case, should I keep user credentials stored locally? If so, how do I do that securely?
Consulted resources
What's the right OAuth 2.0 flow for a mobile app
JWT refresh token flow
Authenticating a mobile application with JWT and refresh tokens
https://softwareengineering.stackexchange.com/questions/318471/jwt-refresh-token-exponentially
https://auth0.com/docs/best-practices/mobile-device-login-flow-best-practices
https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/
https://mobile-security.gitbook.io/mobile-security-testing-guide/general-mobile-app-testing-guide/0x04e-testing-authentication-and-session-management
https://tech.justeattakeaway.com/2019/12/04/lessons-learned-from-handling-jwt-on-mobile/ (more focused on improving an already established architecture)
...and many more I'm not reporting as outside the scope of the question.
This question was originally posted here, https://softwareengineering.stackexchange.com/questions/430302/mobile-authentication-approaches-jwts-and-refresh-tokens/430315#430315
Some diagrams
These are the flows we've currently implemented, working as espected when the API is consumed by a webclient.
Local
OAuth2.0
I don't think the requirement is well formed and it feels like it is based on a sweeping statement from product owners, without considering costs v benefits:
Gmail keeps me signed in forever and I want my app to work like that
LARGE PROVIDERS
The likes of Google often use bespoke solutions around analyzing user patterns, periodically getting 2 factor confirmation and other actions that would be very expensive for normal companies.
OAUTH
For normal software companies the problem has been solved via OAuth and the AppAuth pattern. Curity Guides provide a good starting point if you are not familiar with it:
Once coded you can use many authentication options with zero code changes in your UIs and APIs
User friendly password-less options such as WebAuthn are supported
You can even support advanced options such as App2App Logins if needed
Mobile code and the architecture remains simple in all cases
USER CONSENT
Note also that OAuth is built around users agreeing to the app using their details for a period of time. I often stop and think if I am abusing this - and what would be the impact if a user's device was stolen - not sure how relevant this is for your scenario ...
MIDDLE GROUND
For most companies I would recommend this type of option so that usability is good:
Start with a user friendly option such as 30 day refresh tokens
If you are using password logins, ensure that password autofill works - AppAuth will enable this
TOKENS
These are issued by an Authorization Server (AS) not developed by you. Think of this as a Docker Container that provides HTTPS endpoints - use a free or low-cost one.
The motivation behind the Auth0 point you mentioned is explained well in this article. The mobile app just sends access tokens to APIs. There is no token issuing in your code and it remains simple.
SUMMARY
Prefer industry standard proven options with good cost v benefit results. OAuth is highly architectural though and there is a learning curve which your company needs to manage.
Related
I have a series of JsonAPIs triggers within an Android app.
Question is:
If I have a token for auth. then app's users can easily capture the POST request and find the token, even if I hash the token within the app and send it to server, then compare it to the hashed token from DB users still can capture the hashed token...
Whats a true way to deal with this??
AUTH TOKENS
If I have a token for auth.
Please bear in mind that a User Auth token only identifies who is in the request, not what is doing the request. Don't worry if you were not aware of this yet, because its a very usual misconception among developers of any level and background.
So lets' clear it up first...
The Difference Between WHO and WHAT is Accessing the API Server
I wrote a series of articles around API and Mobile security, and in the article Why Does Your Mobile App Need An Api Key? you can read in more detail the difference between who and what is accessing your API server, but I will quote some of the main points from it:
The what is the thing making the request to the API server. Is it really a genuine instance of your mobile app, or is it a bot, an automated script or an attacker manually poking around your API server with a tool like Postman?
The who is the user of the mobile app that we can authenticate, authorize and identify in several ways, like using OpenID Connect or OAUTH2 flows.
So think about the who as the user your API server will be able to Authenticate and Authorize access to the data, and think about the what as the software making that request in behalf of the user.
EVERYTHING IN THE CLIENT CAN BE CAPTURED OR EXTRACTED
If I have a token for auth. then app's users can easily capture the POST request and find the token, even if I hash the token within the app and send it to server, then compare it to the hashed token from DB users still can capture the hashed token...
No matter what technique you use in the end an attacker can always get hold on any secret you try hard to hide from him, the question is more how much effort he is willing to put in getting it from your mobile app and/or how much knowledge he have to perform such tasks.
Nowadays we have a plethora of tools to help security researchers or anyone one with bad intentions to reverse engineer a mobile app, like:
For MitM atttacks - mitmproxy
An interactive TLS-capable intercepting HTTP proxy for penetration testers and software developers.
For static analysis - MobSF - Mobile Security Framework
Mobile Security Framework is an automated, all-in-one mobile application (Android/iOS/Windows) pen-testing framework capable of performing static analysis, dynamic analysis, malware analysis and web API testing.
For runtime code instrumentation - Frida
Inject your own scripts into black box processes. Hook any function, spy on crypto APIs or trace private application code, no source code needed. Edit, hit save, and instantly see the results. All without compilation steps or program restarts.
Despite this tools exist I still encourage you to employ as many defense techniques as you can afford into your mobile app, because not every attacker as the knowledge or is willing to spent too much time in your mobile app, when they have easier targets to attack.
POSSIBLE SOLUTION
Whats a true way to deal with this??
No true way exists, it's all about your special use case and how much resources you have and can afford to employ and are required by law to do so.
For APIs serving mobile apps you can employ the Mobile App Attestation concept that will allow your API server to have an high degree of confidence about what is doing the request to the API server, is it your genuine and untampered mobile app or is an attacker.
I recommend you to read this answer I gave to the question How to secure an API REST for mobile app?, specially the sections Securing the API Server and A Possible Better Solution.
DO YOU WANT TO GO THE EXTRA MILE?
In any response to a security question I always like to reference the excellent work from the OWASP foundation.
For Mobile Apps
OWASP Mobile Security Project - Top 10 risks
The OWASP Mobile Security Project is a centralized resource intended to give developers and security teams the resources they need to build and maintain secure mobile applications. Through the project, our goal is to classify mobile security risks and provide developmental controls to reduce their impact or likelihood of exploitation.
OWASP - Mobile Security Testing Guide:
The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security development, testing and reverse engineering.
For APIS
OWASP API Security Top 10
The OWASP API Security Project seeks to provide value to software developers and security assessors by underscoring the potential risks in insecure APIs, and illustrating how these risks may be mitigated. In order to facilitate this goal, the OWASP API Security Project will create and maintain a Top 10 API Security Risks document, as well as a documentation portal for best practices when creating or assessing APIs.
So I grant access of my resource to application A, and that application gets that access token. It is just a string. Sometimes the application will pass that access token to its backend server, and then use it to retrieve my resource. Usually the access token is valid for say one month.
Now my question is, what if application A leaks my access token, so any application B can use that access token to get my resource, which is not what I want. I only want application A can access my resource, not application B.
How do we trust application and give it my access token?
YOUR PROBLEM
Usually the access token is valid for say one month.
Using 1 month to the access token expiration time is way to long, not matter if is for admin or normal users.
Depending on your use case I recommend you to use the access tokens with an expiration time in the range of minute, lesser time you can have better will be for security.
So I would recommend you to switch to use refresh tokens, that will keep the access tokens short lived while refresh tokens can be long lived, but in the hours range, not days, weeks or years.
Refresh Token flow example:
Sourced from: Mobile API Security Techniques - part 2
NOTE: While the above graphic belongs to a series of articles written in the context of mobile APIs, they have a lot of information that is also valid for APIs serving web apps and third party clients.
By using the refresh tokens approach, when a client request fails to validate the short lived access token will mean that the client needs to request a new one by sending a refresh token in order to get a new short lived access token.
The important bit here is that the refresh token should not be sent to the browser, only the access token can be sent, therefore your third party clients must kept refresh tokens private, aka in their backends, therefore they MUST NOT send refresh tokens from javascript, instead any renewal of the short lived acess tokens MUST BE delegated to their backends.
Now my question is, what if application A leaks my access token, so any application B can use that access token to get my resource, which is not what I want.
That's why you should use the Refresh Tokens approach I mentioned earlier, because you limit their access to the amount of time remaining in the access token, and this is why I said that the short lived access tokens should be in the range of minutes.
I only want application A can access my resource, not application B.
I am gonna tell you a cruel truth... this is not doable at 100%, specially for web apps, where you can just hit F12 to access the developer tools console and search for the access token, or if you prefer to right click on the page and select view source.
Mobile apps seem to be more secure at a first glance, because they are shipped as a binary, thus you would expect to be hard to reverse engineer it? Wrong, it's indeed easy with the plethora of open source tools that we can use to reverse engineer them, and my preference goes to the MobSF:
Mobile Security Framework (MobSF) is an automated, all-in-one mobile application (Android/iOS/Windows) pen-testing, malware analysis and security assessment framework capable of performing static and dynamic analysis.
So if you cannot find the access tokens via static analysis, then you can resort to dynamic analysis with open source tools to, like Frida:
Inject your own scripts into black box processes. Hook any function, spy on crypto APIs or trace private application code, no source code needed. Edit, hit save, and instantly see the results. All without compilation steps or program restarts.
And if that's is not enough you also perform a Man in the Middle(MitM) Attack wit another open source tools, like mitmproxy:
An interactive TLS-capable intercepting HTTP proxy for penetration testers and software developers.
So, stealing your access token for a mobile app is not as easy as in the Web App, but it's not that hard to.
POSSIBLE SOLUTIONS
How do we trust application and give it my access token?
I don't know if your application is a web or mobile app, therefore I will show you possible solutions for both.
Before I mention the possible solutions, I need to first clear out a usual misconception among developers, regarding who vs what is accessing the backend. This is discussed in detail in this article, where we can read:
The what is the thing making the request to the API server. Is it really a genuine instance of your mobile app, or is it a bot, an automated script or an attacker manually poking around your API server with a tool like Postman?
The who is the user of the mobile app that we can authenticate, authorize and identify in several ways, like using OpenID Connect or OAUTH2 flows.
If you still have doubts please go and read the section of the linked article, that also includes a graphic to help with understanding this. The article is in the context of a mobile app, but for understanding the difference between what and who is accessing the backend, the references to mobile app can be replaced with web app.
For Web Apps
If your use case is a web app the most affordable solution to try to mitigate the who vs what is accessing your backend it's by using:
Google Recaptcha V3:
reCAPTCHA is a free service that protects your site from spam and abuse. It uses advanced risk analysis techniques to tell humans and bots apart.
This is uses User Behaviour Analytics(UBA) in a best effort basis to tell appart who and what is accessing your backend.
User behavior analytics (UBA) as defined by Gartner is a cybersecurity process about detection of insider threats, targeted attacks, and financial fraud. UBA solutions look at patterns of human behavior, and then apply algorithms and statistical analysis to detect meaningful anomalies from those patterns—anomalies that indicate potential threats.[1] Instead of tracking devices or security events, UBA tracks a system's users.
This is prone to false positives, therefore you need to be careful when deciding to accept or not the request based on the score returned by reCPATCHA V3 for each request:
reCAPTCHA v3 returns a score for each request without user friction. The score is based on interactions with your site and enables you to take an appropriate action for your site.
For Mobile Apps
As you saw by the plethora of tools available to reverse engineer the mobile apps, statically or dynamically, the access token to identify your user is not that safe, plus this only identifies the who in the request, not what is doing it.
The solution that can let your backend to be sure that the request is indeed from the same exact mobile app that was uploaded to the Google Play or Apple store is a Mobile App Attestation solution, that is a concept that introduces a new way of dealing with security for your mobile app and backend in an unified manner.
The usual approaches focus to much on the mobile app side, but in first place the data you want to protect is in your backend server, and it's here that you want to have a way to know that what is making the request is really the thinh you expect to be, your genuine mobile app.
The Mobile App Attestation concept is described in this section of another article I wrote, from where I will quote the following text:
The role of a Mobile App Attestation service is to authenticate what is sending the requests, thus only responding to requests coming from genuine mobile app instances and rejecting all other requests from unauthorized sources.
In order to know what is sending the requests to the API server, a Mobile App Attestation service, at run-time, will identify with high confidence that your mobile app is present, has not been tampered/repackaged, is not running in a rooted device, has not been hooked into by an instrumentation framework (Frida, xPosed, Cydia, etc.) and is not the object of a Man in the Middle Attack (MitM). This is achieved by running an SDK in the background that will communicate with a service running in the cloud to attest the integrity of the mobile app and device it is running on.
On a successful attestation of the mobile app integrity, a short time lived JWT token is issued and signed with a secret that only the API server and the Mobile App Attestation service in the cloud know. In the case that attestation fails the JWT token is signed with an incorrect secret. Since the secret used by the Mobile App Attestation service is not known by the mobile app, it is not possible to reverse engineer it at run-time even when the app has been tampered with, is running in a rooted device or communicating over a connection that is the target of a MitM attack.
The mobile app must send the JWT token in the header of every API request. This allows the API server to only serve requests when it can verify that the JWT token was signed with the shared secret and that it has not expired. All other requests will be refused. In other words a valid JWT token tells the API server that what is making the request is the genuine mobile app uploaded to the Google or Apple store, while an invalid or missing JWT token means that what is making the request is not authorized to do so, because it may be a bot, a repackaged app or an attacker making a MitM attack.
So this approach will let your backend server to trust with a very high degree of confidence that the request is coming indeed from the same exact mobile app you uploaded to the Google Play and Apple store, provided the JWT token has a valid signature and expire time, and discard all other requests as untrustworthy ones.
GOING THE EXTRA MILE
To finish my answer I cannot resist to recommend you the excellent work of the OWASP foundation, because off their excellent work and for me no security solution for web and mobile is complete without going through their guides:
The Web Security Testing Guide:
The OWASP Web Security Testing Guide includes a "best practice" penetration testing framework which users can implement in their own organizations and a "low level" penetration testing guide that describes techniques for testing most common web application and web service security issues.
The Mobile Security Testing Guide:
The Mobile Security Testing Guide (MSTG) is a comprehensive manual for mobile app security development, testing and reverse engineering.
I'm having trouble understanding how ASP.NET Core authentication works.
I want to implement JWT access token authentication with refresh tokens. To my knowledge, this is the industry standard for authenticating a client (Mobile app, SPA Web application). For security purposes, I'd prefer to not implement my own authorization logic including JWT generation and refresh token handling. Since ASP.Net does not natively support this, Naturally my choice would be to use IdentityServer4, a large open source library for handling this kind of stuff.
However IdentityServer4 is heavily based on OAuth, and I'm not sure how that works with SPA applications and mobile apps (clients I trust). It requires the client to redirect to some arbitrary webpage to enter their credentials and then redirect back to the app. Gross. I've never seen a major app like Snapchat, Instagram, etc. have this kind of authentication flow where you are directed to some webpage/browser during the login flow. Luckily IdentityServer4 has a little feature to handle username/password authentication for my trusted clients (http://docs.identityserver.io/en/latest/quickstarts/2_resource_owner_passwords.html)
Great, that seems to suit my needs. But... Now I want to add Facebook Authentication. IdentityServer4 allows for External Authentication, however it is still cookie based (to my knowledge). Which requires the Android/iOS/SPA app to redirect to a webpage and then redirect back to the app. Again, this isn't ideal from a user perspective. Facebook provides native mobile SDKs to handle this type of authentication which returns an access token so there is no need to redirect to web pages using cookies.
Now lets say my iOS app uses the Facebook SDK to grab an access token for the user and sends it to the backend. The backend validates the token against the Facebook SDK, and subsequently registers a local user in it's own database.
Now when that same iOS user tries to login to the app, the app will generate a facebook access token for that user from the SDK and send it to the backend. However I'm not sure how to utilize IdentityServer4 to generate a JWT for the user since I need that users' username and password. This is where I'm stuck. I seem to be fighting against the library which makes me believe I am severely misunderstanding something.
TLDR; IdentityServer4 seems to be heavily based on cookies which doesn't really fit nicely into mobile apps/SPA webpages when you are redirected back and forth from authentication webpages. Am I using the wrong tool for the job? What are some alternative solutions?
As a note on big social apps: I think it comes down to who keeps the passwords. Facebook, Instagram, Snapchat, Google act as identity providers to third parties. They themselves require user to register and specify the password which they keep. Therefore they can use any customized approach for handling validation with those passwords. However, if any of them offerred a posibiltty to log-in with the other I.e Instagram were allowing to sign-in with Amazon credentials, then they would need to follow through a standard way like OAuth and redirect to the third party for log-in. Last time I checked Instagram, Facebook and Snapchat only offer to register and no option to sign in with 3rd parties which explains why the don't need redirects.
Now if we establish that a redirect is a necessary evil, then the means to carry over the data accross aren't that numerous. I.e. we either would need to pass data via a query string or use cookies. Am I missing any others?
Both have limitations but since cookies are persisted and browser carries them automatically with each request, they do seem like a better option for the job, especially if multiple redirects are required for an external IdP to track the state of authentication request. The same reason is mentioned here:
http://docs.identityserver.io/en/latest/topics/signin_external_providers.html
It's absolutely the right tool for the job if you want what OpenID Connect and OAuth2 give you. It sounds like you may need convincing though and it may be that your use case doesn't need the full breadth of functionality offered.
If you have multiple client applications and APIs in play then I think using OpenID Connect and IdentityServer4 the right choice at this point in time.
Regarding native apps, you used to word "gross" to describe using the user's default browser to perform the sign in process and it's understandable why you might think that at first but it's not as bad of a UX as you'd think and has plenty of advantages:
The client application is completely decoupled from how authentication is actually done be that federation, social sign in (Facebook in your case), multi-factor, retina scan etc. Your identity server deals with all that complexity and is a single point of management (and failure - so make it highly available!)
Single sign on is possible - if they're already signed into your IDP then they can go straight in (although you have full control of the flow - want them to consent or confirm the sign in request every time - you can do that)
If the user has a password manager set up in their browser then that'll work too
Both iOS and Android offer APIs for doing this stuff and the work well. If you skin your native and web UIs to look similar the flow from a user's PoV is not jarring at all.
You can still use refresh tokens (ultimately secured by the platform) so you don't actually have to do the interactive flow very often anyway.
Some additional reading below. Quite a lot of thinking has gone into this from the industry so it's definitely worth digesting the current best practice.
https://developers.googleblog.com/2016/08/modernizing-oauth-interactions-in-native-apps.html
IETF current best practice: https://www.rfc-editor.org/rfc/rfc8252
Don't make Scott hate you ;) : https://www.scottbrady91.com/OAuth/Why-the-Resource-Owner-Password-Credentials-Grant-Type-is-not-Authentication-nor-Suitable-for-Modern-Applications
For client side SPA browser apps OIDC provides the implicit grant type and uses a silent refresh and IDP session monitoring mechanism to maintain the session. Check out the oidc-client-js library which implements this approach.
I would like to secure my mobile app ( hybrid app, build with ionic framework). On backend site I use the play framework. I would implement the following case. The user of the app should authenticate to rest backend by email and password, if the credentials correct the backend generates an token return ok with the generate token to client, otherwise the backend return bad request. If the user would try to login with incorrect credentials more then 10 times the user would deactivated for 1 hour.
The mobile app would load json data from backend with ajax calls, on each call in header would set the field 'X-AUTH-TOKEN' and the generate token. The backend check the token and if the token is correct the client get data from server with status ok else the client get none data and the status unauthorized. If the user logged out the token would destroyed on server and client side. The token would not change as long as the user is logged in, in worst case the token would not changed over more than many days. I could implement, that on each call the date of last call can saved and if the last call is more than x days in past the server return unauthorized and destroy the token. So the user should logged in. Is the case secure enough, or should I implement more logic?
What you are describing is very similar, if not identical to the many, many implementations of OAuth2. For more information on these types of flows, including diagrams, check out how Google describes their OAuth2 processes here: https://developers.google.com/accounts/docs/OAuth2
I'm not familiar with the play framework but you should speak with framework experts to see if there is a well-tested, battle-hardened oauth2 implementation out there for the Play Framework. If so, you want to use that. You really don't want to (and shouldn't) roll your own implementation unless you know what you're doing and are willing to pay for people to pentest it. Really, please don't do this if unsure.
On the Ionic Framework / Angular / Cordova side, you've basically got it correct, but should always consider some basic security considerations:
My guess is that you'd use local storage to store the access token. In REST we don't have sessions like in a traditional web server scenario so we use the token in lieu of the session. Of course the downside is that local storage can easily be inspected to obtain the access key if someone had either root access on the device and was able to work their way into the app sandbox and knew exactly what api key to grab from local storage, but if someone has root or physical access to the device then you've got a bigger problem, so this isn't a design flaw per-say. To a certain extent, using this method you're relying upon the OS/browser's local storage sandbox to prevent other apps from accessing the local storage in your ionic app. This is a bet I would be willing to make, but you'll need to judge that based on your security vs usability needs.
What you should really be focusing on is protecting the token from people who may be listening on the wire (think coffee shop wifi). This means setting up your auth rest servers to use exclusively HTTPS (don't fail back to HTTP). This may have downsides, but will be worth it to protect your user's data. You also correctly identified using the token header. You should never pass auth tokens in anything but the header or POST data.
Generally speaking, what you are describing should be safe for use in a consumer level app. This assumes you don't unwittingly use any malicious third party code in your app. As always, you should be especially wary of third party code and only use code that you absolutely trust. Any code run from inside your app can access local storage in the Cordova/browser local storage sandbox and could theoretically export the api token for use in other software to access your api. With that said, you asked about authentication and not authorization. Keep in mind that your users need to only have access to do certain things in the app based on user-roles or some sort of ACL. This authorization outside the scope of this answer but you need to ensure that this is done on the server side and has rate limiting or soft-deletes for shared resources to prevent a malicious user from deleting everything.
Good luck with ionic and have fun.
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