Authentication for isomorphic web app with separate website and API servers - api

I have developed a stateless API on a server at api.com. Some API endpoints require authentication.
I have a website on a separate server at website.com. When a user authenticates with the website, the website server needs retrieve some data from an API endpoint which requires authentication (/tweets, for example). This data will be used in the server response (to render the tweets, for example).
The server response will also download some JavaScript in the browser that will subsequently need to retrieve (via XMLHttpRequests (XHR)) some data from an API endpoint which requires authentication (/tweets, for example).
This architecture represents an isomorphic web application. The server renders the whole page when requested, and thereafter the client handles user actions using JavaScript.
--
At a very basic level, I could use HTTP Basic Authentication for both website.com and api.com. However, the browser would prompt the user to enter their credentials when they first login to website.com, and repeatedly when the client makes an XHR to a endpoint requiring authentication.
I want the user to login with their credentials once at website.com. This is similar to the current Twitter website. Once you login to twitter.com, the website server identifies you as authenticated and responds with a HTML page containing JavaScript downloads. The JavaScript app then (presumably) makes authenticated XHRs to the stateless Twitter API.
The API is a separate server by design. Eventually the API could be opened up for third parties, although this is not an initial requirement.
How can I achieve this? I'm looking for:
the simplest secure solution
a solution that uses OAuth (if applicable)
Both would be great!

The situation you describe is exactly what OAuth is designed for: a client authorizes with one server and then obtains access to resources on another server. In your case, website.com is the authorization server and api.com is the resource server. In a nutshell, the authorization server sends an access token to the client, which the client can then pass on to the resource server to prove that they have permission to access the resource. In order for this to work, the resource server (api.com) needs to either check back with the authorization server (website.com) to verify that the token is valid or be informed about the token in advance. So there is a triangle of communication between the client, the authorization server and the resource server in which a shared secret is passed around. Because of this, it is absolutely necessary to use secure connections (HTTPS) in all parts of the chain; otherwise, someone could intercept the token and pretend to be the authorized client. This is kept within reasonable bounds by using limited-access tokens which do not fully authenticate the user, but it is nonetheless a problem that you should try to prevent.
While theoretically secure, OAuth is a complicated system and it is hard to get right. Some people think it is practically impossible to get right (notably Eran Hammer, the original lead author of the OAuth 2.0 specification who decided to withdraw from the working group). However, given that you need to use HTTPS anyway, you could avoid OAuth altogether and instead use a little-known builtin feature of HTTPS (or actually, TLS) called (surprise!) client authentication.
As you probably already know, in the HTTPS protocol, the server (website.com) uses a certificate signed by a trusted authority to authenticate itself. This is a well understood and very secure mechanism (at least by internet standards), provided that the certificate is uncompromised and that the latest version of TLS is used. The client can do the same, i.e. authenticate with a certificate that was signed by a trusted authority. The latter authority can be the server (website.com) for this purpose, because the server can trust itself. So the elegance of TLS client authentication is that the client does not need to contact a third party in order to obtain a certificate; the client and the server can cooperate to provide the client with a certificate that the server can trust. This is potentially even very user-friendly, because the client certificate needs to be transferred and installed only once and can then be used for authentication on subsequent sessions, possibly without the user even needing to enter a password. The same client certificate can also be used for HTTPS connections with other servers (e.g. api.com), provided that those servers know about the certificate and trust the authority that signed it (website.com).
TLS client authentication is likely to be more secure than OAuth, while it might require less interaction from the user overall (depending on the way in which the client certificate is handled in the browser). On the other hand, most users are probably unfamiliar with the particular mechanics of TLS client authentication. If users need to log in from many different devices or need to authenticate to many different servers, this workflow may be confusing or cumbersome because each device needs to have a certificate and the certificate may have to be selected manually by the user when a new server is visited for the first time.
To summarize:
In both cases, website.com provides the client with a means to authorize for access to api.com, which api.com needs to know about. So api.com cannot be 100% stateless; it needs to have some knowledge about the means of authorization that website.com communicated with the client.
Both cases require a secure connection (HTTPS).
In OAuth, the means to authorization is a "shared secret" limited access token (also known as "pseudoauthentication"), while in TLS client authentication, it is a private certificate that fully authenticates the client because it was signed by a trusted authority.
In OAuth, authorization is done on the data layer (applications explicitly communicate the access token) while in TLS client authentication, authentication is done on the transport layer (meaning that your API does not actually need to be aware of authentication or even authorization, if the webserver is configured to allow certain endpoints only to authenticated clients).
TLS client authentication is probably more trustworthy, but OAuth is probably more familiar to users because it works with password logins "as usual".
Some clarifications in response to the comments:
How does website.com know the user is logged in? How does website.com remember the user is logged in (i.e. between browser refreshes)?
By storing the access token in a secure cookie on the client side. On every request from the client to website.com, the access token is included in the request headers. This way, website.com can be assured that every request is either authenticated (if the request contains the access token, i.e. the user is logged in), or the visitor is a guest.
How does the browser make authenticated XHR requests?
By sending the access token in the request header, just like for website.com. Obviously, this requires the cookie to be accessible to the client.
website.com needs to authenticate with api.com when creating the server response
When it does that, it just sends a (HTTPS) request on the user's behalf. It's the same thing where the access token is included in the request headers. website.com always has the access token of the user when it does this, because it either is about to provide it to the user or it just received it from the user.
Further information on Wikipedia:
https://en.wikipedia.org/wiki/Oauth
https://en.wikipedia.org/wiki/HTTP_Secure#Use_as_access_control
https://en.wikipedia.org/wiki/Transport%5FLayer%5FSecurity#Client-authenticated%5FTLS%5Fhandshake

As Julian mentioned OAuth is complicated and hard to get right. I would find a trusted opensource project and use that as your Identity Server.
Also, instead of OAuth, I would look into OpenID Connect. It is a relatively new protocol (Jan 2014), but has been getting a lot of attention. Google+ for example is using it. It combines the authorization framework of OAuth and adds the identity and authentication framework on top. OAuth was never truly designed for that, which is one of the reasons why Eran left the project. This new protocol is the future of Single Sign On and will replace WS-Federation and SAML. http://openid.net/connect/
Here are all the current libraries available: http://openid.net/developers/libraries/
Again, if you're using C#/.NET, here is their project currently in Beta 3 (should be live in Januaray) that provides every possible configurable scenario with examples. If nothing else, it gives you the code to see how you can implement it. https://github.com/thinktecture/Thinktecture.IdentityServer.v3.Samples
See this talk for more details: http://vimeo.com/97344501
Hopefully this gives you some food for thought.

I think something like this can be done
1) User logs in at website.com, website.com will create a temporary token T for future API usage
2) Whenever some data is required from api.com, website will request that data and send token T in the request api.com/getdata/params=...&token=T
This request is better done with SSL to protect the token.
Please also check http://en.wikipedia.org/wiki/Cross-origin_resource_sharing - not all browsers will let you request data from another domain from Javascript.
3) When api.com receives such a request, it will make a separate and secret connection to website.com, something like website.com/checktoken/?token=T and get all necessary information about the user at website.com to send him relevant data
4) User gets all information, not leaving website.com and not having to authenticate at two places

Basically, you need to decide whether you want to authorize website.com domain to use api.com methods, or to authorize users of website.com to use api.com. From your description I understand that your are talking about the second case.
Then some kind of OAuth(OAuth2.0) implementation could be suitable for you with(probably) a single authentication point for the all your sites: it could be the passport.com. When user wants to use api.com or website.com or any other your site, he will be redirected to passport.com and required to authenticate there. After authentication on passport.com, user will be redirected back and provided with authorization code, that is used to request token, that, in turn, could be used by api.com and website.com to get information about the user(roles, permissions etc). On website.com you could use this token to access api.com, because api.com could use this token to validate user against passport.com. Also you could use this token to request info from api.com by AJAX(you need to overcome the Same Origin Policy problem, though, but it's feasible).
UPDATE:
The idea is that user needs to be authenticated on passport.com to use website.com & api.com.
From the OAuth2.0 standpoint you could say that user authorizes website.com & api.com to use his info on passport.com.
So authentication cookie exists only for passport.com domain and
is not sent anywhere else(to website.com or api.com). This is according to the Same Origin Policy.
So more detailed description of OAuth2.0 implementation in your case would be:
User wants(or have to) to be authenticated on website.com. Request to the passport.com is performed(with specified REDIRECT_URL on website.com where to return later): passport.com/auth/?redirectTo=REDIRECT_URL
If user is not authenticated on passport.com(there is no Auth cookie there) then login page of passport.com is displayed to him. When authenticated, new AUTHORIZATION_CODE is saved on passport.com(in database) for that user.
After authentication on passport.com(or if user already was authenticated there) passport.com redirects user back to REDIRECT_URL with AUTHORIZATION_CODE in querystring: {REDIRECT_URL}?code=AUTHORIZATION_CODE
Website.com uses this AUTHORIZATION_CODE to request ACCESS_TOKEN from passport.com:
passport.com/token/?code=AUTHORIZATION_CODE
Having ACCESS_TOKEN, website.com could use it to request information about user from passport.com. Plus you could pass this ACCESS_TOKEN to api.com when requesting something from api.com. api.com could check user's identity against passport.com to check if he has enough permissions. Is it safe to pass ACCESS_TOKEN to api.com? You need to provide some sort of key to api.com anyway(if api.com is not a public api), so using this approach at least ACCESS_TOKEN is not a static one: it has lifetime, and it's user-based.
Again, it's very simplified OAuth2.0 example without secret keys, scopes, access grants and few other details.

Here is a simple way. It adds some overhead/latency, but at least it works and is dead simple:
let website.com act as a proxy and forward all calls to api.com
browser <-> https://website.com/api/url <-> https://api.com/url
You can just reuse the creditentials to make a separate session from website.com to api.com

Related

Separate authentication and authorization servers for SPA app

I have
UI (a single page app)
an external authentication server
my own authorization server
resource server (my own backend APIs)
Here's what I am trying to do
UI/User gets an AuthN token from the external authentication server.
UI sends the AuthN token to get the an AuthZ token from my own authorization server
UI uses the AuthZ token to retrieve data from the resource server
But the problem is I don't know if the user is still authenticated anymore because I stopped using the AuthN token from step 3. Should I use both tokens together? or somehow consolidate the 2 tokens into one? Hope to get some ideas from here. Thanks!!
COMPONENTS
This is the standard way of managing components:
UI makes an OpenID Connect redirect to the Authorization Server (AS)
AS makes a second OpenID Connect redirect to the authentication system. There could be more than one of these, eg Google, Facebook.
After user sign in the AS issues the same tokens for your UI and resource server, regardless of how the user signs in. The UI sends access tokens to the resource server which can authorize based on scopes and claims received.
Unless you have special reasons, do not use foreign tokens from authentication systems in your own applications. This is because you are not in a position to control their contents.
OPENID CONNECT RE-AUTHENTICATION MECHANISMS
The OpenID Connect prompt and max-age parameters can be used to control how frequently the user is prompted to re-authenticate, and the auth_time claim can be issued in ID tokens to inform the UI of the last authentication time.
For example your app could use access tokens that last 15 minutes. Whenever they expire you could send a request with a prompt-none parameter to see if the user is still authenticated. If not then you will receive a login_required response and you could then redirect the user to re-authenticate.
SINGLE LOGOUT
Knowing if the user is still authenticated suggests you need to know if they signed out in another app. OpenID Connect has four Single Logout Mechanisms that you should be aware of, and which may possibly work for your scenario.
This is a technical area that has never worked perfectly in any Single Sign On technology though. This may be because you do not control all apps, or because of technical limitations, eg Google may not inform the Authorization Server if the user signs out of Gmail.
SUMMARY
Your apps should only use the authorization server tokens. Use OIDC request parameters to control when the user must re-authenticate.

How to authenticate SPA users using oAuth2?

Alright, I've spent several days looking for a proper solution on how to properly authenticate users when working with SPAs.
I have my own website.
I have my own API.
I have my own Single Page Application.
I have my own database of users.
The Goal: I need to get an access_token by providing a username and a password.
I looked at OAuth2 Implicit Grant, but it requires users to Approve/Decline the app after successful authentication. It doesn't work in my case since I own both the app and the API.
I looked at OAuth2 Password Grant, which is not perfect since I need to expose client_id/client_secret.
The reason I'm looking at OAuth2 is because the API will eventually be public.
Is there a standard way of doing this? My current options:
Forget about OAuth2 and manually generate access_token when user POSTs username/password (in this case I'd have to introduce OAuth2 when API goes public)
Use OAuth2 Password Grant and inject client_id/client_secret on the server, so just to keep client app very simple (also avoid all of those dev/staging/prod client_id/client_secret pairs)
Implicit Grant
You are right that Implicit grant type does not look appropriate. But I think your reason for not favoring it is incorrect because the approval step is not mandatory and in Spring OAuth 2 implementation (I don't know which implementation you are using) you can configure the Authorization server to auto approve authorization requests so that the approval step is skipped.
The reasons I think the "Implicit flow" is not suitable are
​The client authentication step by providing client secret and authorization code is missing. So less security.
The access token is sent back as a URL fragment (so that the token doesn't go to the server) which will continue to stay in browser history
If XSS attack occurs, the malicious script can very well send the token to the remote server
Resource Owner Password Credentials Grant
If the authorization server and the resource server are the same, I think this is a quick way of getting up and running. RFC 6749 in Section 4.3.2 says:
If the client type is confidential or the client was issued client credentials (or assigned other authentication requirements), the client MUST authenticate with the authorization server as described in Section 3.2.1.
This means that the client authentication with client secret is not mandatory here. Now, for authorization code grant type, we need the client secret because the user provides his/her credentials directly to the authorization server and then when the client requests for the access token, it doesn;t have anything else other than the client secret to prove to the authorization server that this is a genuine request.
But in case of resource owner password credential grant type, the user has provided its credentials to the client itself and the client will then send these same user credentials for requesting access token. Therefore, the access-token request can be authenticated with the user credentials only and if we don't provide a client secret here, I don't think we are losing anything in terms of security.
So, you can definitely use password credential grant type in your SPA.
Authorization Code Grant
I think this should be the preferred option provided the client secret is not stored in the browser. After user authentication (and optionally user approval), the authorization server can redirect the browser to a server side endpoint with the authorization code in the URL. The server side end point will the request for the access token using the authorization code, client id and client secret (which is stored in the server side only). Once the access token is available, the server side endpoint can redirect (HTTP response code 302) the user to the SPA URL with appropriate cookies for CSRF protection and access token. Thus we are not storing the client secret in the browser.
By using authorization code grant type, you are basically making the solution more secured and generic. In future, if you want to do a single sign-on with a different SPA, you can do that easily by reusing the same authorization server with its integration with the authentication database (preferably an LDAP server).
For further details, refer to my StackOverflow answer here.
Building off what has been said already, I would recommend the 'Authorization Code Grant' but with the addition of the PKCE (Proof Key for Code Exchange / 'pixie') extension - for added security, regardless of whether you're implementing a 'public' or 'confidential' type client.
With PKCE, you don't need a client-secret for public clients (/it's kind of like generating a temporary client-secret at the very outset/beginning of each authentication attempt/instance - although even with PKCE for confidential clients you should ideally still use a client secret).

Secure Web Authentication and API access

I want to design a web application which guarantees secure authentication and gives API access only to the authorised users. The basic idea is simply sending username and password to get the user authenticated. And user can make request to server with the session_id without authenticating himself again.
Definitely, it is very insecure. But as far as I could understand now, in order not to expose the user's credentials, we can apply TLS(https) to get it encrypted.
However, as I research around, I get acquainted with a lot of concepts, like Base64, HMAC_SHA1, API keys, OAuth1.0. But I could not understand why do we need those mechanism other than TLS. Can anyone help explain why TSL is not enough to ensure authentication and API access to be secure?
Secure sessions work fine if your web application authenticates the user, issues the session id and validates the id on each call. You can store the session id in a secure cookie that gets sent back on each request.
Things get more complicated when you have your API on a different domain. Now your cookies are not automatically sent to the service (same-origin policy). You could of course stick the session id in an Authorization header when you call your API. But now your API needs to talk to the same backend store maintaining your session state to verify the authorization. This backend store becomes a bottleneck in scalability and a single point of failure.
To get around this, modern protocols (like OAuth2) issue security tokens. These tokens are digitally signed (using HMAC) and the receiver trusts the token if the signature is validated successfully. No backend calls are needed to validate the token, just a simple cryptographic operation.
API keys are used to allow applications to get a security token without relying on a user to authenticate. Think of them as a password for an application.
Using security tokens also allows you to use a 3rd party authorization server (like Facebook or Google etc) and completely get out of the business of authenticating users, storing passwords, issuing tokens etc.

Single sign-on flow using JWT for cross domain authentication

There is a lot of information on the web about using JWT (Json Web Token) for authentication. But I still didn't find a clear explanation of what the flow should be when using JWT tokens for a single sign-on solution in a multiple domains environment.
I work for a company which has a lot of sites on different hosts. Let's use example1.com and example2.com. We need a single sign-on solution, which means if a user authenticates on example1.com, we want him to also be authenticated on example2.com, automatically.
Using the OpenId Connect flow, I understand that the user who wants to authenticate on example1.com will first be redirected to the authentication server (or OP : "OpenId Provider"). The user authenticates on that server which then redirects him back to the original example1.com site with a signed JWT token. (I understand there is another flow which returns an intermediate token that itself can be exchanged for the real JWT token later on, but I don't think this is required for us)...
So now the user is back on example1.com and is authenticated! He can make requests, passing the JWT token in a Authentication header and the server is able to verify the signed JWT and therefore is able to identify the user. Nice!
First question :
How should the JWT token be stored on the client? There is, again, a lot of information about this, and people seem to agree that using Web Storage is the way to go rather than good old cookies. We want the JWT to be persistent between browser restarts so let's use Local Storage, not Session Storage...
Now the user can restart his browser and he will still be authenticated on example1.com, as long as the JWT token is not expired!
Also, if example1.com needs to make an Ajax request to another of our domains, I understand configuring CORS would allow that. But our main use case is not cross-domain requests, it's having a single sign-on solution!
Therefore, the main question :
Now, what should the flow be, if the user goes to example2.com and we want him to be authenticated, using the JWT token he already has? Local Storage doesn't seem to allow cross-domain access so at this point the browser can't read the JWT token to make requests to example2.com!
Should :
The user be redirected to the authentication server again? When the user authenticated for example1.com, the
authentication server may have set a cookie on the user so this new authentication request for example2.com could use that cookie to see that the user is already authenticated and immediately redirects him back to
example2.com with the same JWT token?
Or can the browser, on example2.com, access the JWT token without having to go to the authentication server again? I see there are cross-storage solutions, but are those widely used? Are they the suggested solution to a cross domain SSO environment?
We don't want anything fancy, we would be happy with the mostly used solution!
Redirecting the user to the central authentication service when the user is not logged in to request credentials and issue a new authentication token is the common scenario in Single Sign On systems using well-known protocols like oauth2 or OpenId Connect
However when this schema is used across domains the main drawback is that the user is going to be redirected and authenticated each time he navigates to other domain due to same-origin policy: the access token can not be shared between domains (example2.com can not access data of example1.com), so the target domain will treat user as unauthenticated, redirecting him to the central SSO service.
To prevent the authentication service from re-requesting credentials, it is common to have a session cookie (not an access token), but there is a tecnique to share data across domains using browser localStorage/cookies and a iframe pointing to an intermediate domain sso.example.com
To authenticate the user in example1.com, redirect him to the authentication server in sso.example.com, issue a JWT after authenticating and store it in the localStorage of this domain. After this, redirect user to the origin domain example1.com
Create an iframe in example2.com pointing to sso.example.com. The iframe in sso.example.com reads the JWT token and sends a message to the parent page
The parent page receives the message and gets the attached token continuing with the SSO flow
There is no problem with same-origin policy because sso.example.com has access to its localStorage and the communication between iframe and the parent page is allowed if origin and target domains recognize each other (see http://blog.teamtreehouse.com/cross-domain-messaging-with-postmessage)
To simplify development, we have released recently a cross domain SSO with JWT at https://github.com/Aralink/ssojwt
This method is perfectly compatible with SSO flows. It is just a way to share the authentication token without redirections and avoid unnecessary log-ins when the domains are federated
The user should be redirected to the authentication server again and get a new token (JWT), one that is specifically targeted for example2.com. This is how OpenID Connect and any other cross-domain federated SSO protocol works.
Not sure if this answers you question, but if your main goal is single sign-on, I think a simple reverse proxy would solve your problem (at least the cross-domain storage one).
So
example1.com
example2.com
would become something like
example.com/example1
example.com/example2
(And from a user side, this is usually cleaner)
If that is not an option, you might have to set up so that when a user authenticates in 1 domain, it uses AJAX/hidden iframes to create an authentication with the other domains as well (sending a 1 time token via url if you must).
and if THAT'S not an option, you might have to resort to username+pin, as browsers are getting stricter about cross-domain interaction.

REST API authentication for web app and mobile app

I'm having some trouble deciding how to implement authentication for a RESTful API that will be secure for consumption by both a web app and a mobile app.
Firstly, I thought to investigate HTTP Basic Authentication over HTTPS as an option. It would work well for a mobile app, where the username and password could be stored in the OS keychain securely and couldn't be intercepted in transit since the request would be over HTTPS. It's also elegant for the API since it'll be completely stateless. The problem with this is for the web app. There won't be access to such a keychain for storing the username and password, so I would need to use a cookie or localStorage, but then I'm storing the user's private details in a readily accessible place.
After more research, I found a lot of talk about HMAC authentication. The problem I see with this approach is there needs to be a shared secret that only the client and server knows. How can I get this per-user secret to a particular user in the web app, unless I have an api/login endpoint which takes username/password and gives the secret back to store in a cookie? to use in future requests. This is introducing state to the API however.
To throw another spanner into the works, I'd like to be able to restrict the API to certain applications (or, to be able to block certain apps from using the API). I can't see how this would be possible with the web app being completely public.
I don't really want to implement OAuth. It's probably overkill for my needs.
I feel as though I might not be understanding HMAC fully, so I'd welcome an explanation and how I could implement it securely with a web app and a mobile app.
Update
I ended up using HTTP Basic Auth, however instead of providing the actual username and password every request, an endpoint was implemented to exchange the username and password for an access key which is then provided for every authenticated request. Eliminates the problem of storing the username and password in the browser, but of course you could still fish out the token if you had access to the machine and use it. In hindsight, I would probably have looked at OAuth further, but it's pretty complicated for beginners.
You should use OAuth2. Here is how:
1) Mobile App
The mobile app store client credentials as you state yourself. It then uses "Resource Owner Password Credentials Grant" (see https://www.rfc-editor.org/rfc/rfc6749#section-4.3) to send those credentials. In turn it gets a (bearer) token it can use in the following requests.
2) Web site
The website uses "Authorization Code Grant" (see https://www.rfc-editor.org/rfc/rfc6749#section-4.1):
Website sees unauthorized request and redirects browser to HTML-enabled autorization endpoint in the REST api.
User authenticates with REST service
REST site redirects user back to website with access token in URL.
Website calls REST site and swaps access token to authorization token.
Here after the website uses the authorization token for accessing the REST service (on behalf of the end-user) - usually by including the token as a "bearer" token in the HTTP Authorization header.
It is not rocket science but it does take some time to understand completely.
3) Restricting API access for certain applications
In OAuth2 each client is issued a client ID and client secret (here "client" is your mobile app or website). The client must send these credentials when authorizing. Your REST service can use this to validate the calling client
I resolved this for my own API quite easily and securely without the need to expose any client credentials.
I also split the problem into 2 parts. API authentication - is this a valid request from a recognised entity (website or native app). API authorisation, is that entity allowed to use this particular endpoint and HTTP verb.
Authorisation is coded into the API using an access control list and user permissions and settings that are set up within the API code, configuration and database as required. A simple if statement in the API can test for authorisation and return the appropriate response (not authorised or the results of processing the API call).
Authentication is now just about checking to see if the call is genuine. To do this I issue self signed certificates to clients. A call to the API is made from their server whenever they want - typically when they generate their first page (or when they are performing their own app login checks). This call uses the certificates I have previously provided. If on my side I am happy the certificate is valid I can return a nonce and a time limited generated API key. This key is used in all subsequent calls to other API endpoints, in the bearer header for example, and it can be stored quite openly in an HTML form field or javascript variable or a variable within an app.
The nonce will prevent replay attacks and the API key can be stolen if someone wants - they will not be able to continue using after it expires or if the nonce changes before they make the next call.
Each API response will contain the next nonce of if the nonce doesn't match it will return an authentication error. In fact of the nonce doesn't match I kill the API key too. This will then force a genuine API user to reauthenticate using the certificates.
As long as the end user keeps those certificates safe and doesn't expose the method they use to make the initial authentication call (like making it an ajax request that can be replayed) then the API's are nice and secure.
One way of addressing the issue of user authentication to the API is by requesting an authentication token from the API when the user logs in. This token can then be used for subsequent requests. You've already touched on this approach - it's pretty sound.
With respect to restricting certain web apps. You'll want to have each web app identify itself with each request and have this authentication carried out inside your API implementation. Pretty straight forward.