Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Session design of an Application server API with multiple client platforms

I'd like to build an app that'll support multiple platforms: Desktop applications (Mac/PC), Web (angularJS fronted) and native mobile apps.

So I'm thinking of an application server, serving internal APIs to the platforms above. I have certain assumptions regarding how login/logouts are to be supported. I would be happy if anyone could comment if my thinking is wrong.

  1. For desktop and mobile apps, the "login" function will use the internal API to communicate the credentials and in return will receive a permanent token. the desktop/mobile app will store the token and use it with any subsequent request to the application server. Upon "logout" from the desktop/mobile app, the token will be discarded on the server side an forgotten on the front end app side.
  2. For the web interface, the angular application will retain the token provided after login as a cookie and will load it up and use it with any request made to the application server.

Is this a common pattern?

like image 392
JasonGenX Avatar asked Sep 30 '16 15:09

JasonGenX


4 Answers

You have the basic structure correct, however with OAuth2 you will never be storing the access token forever. The access token is often an opaque string that grants access to your API, storing it in a cookie or local storage is fine, but issuing a token from the server that never expires would be highly inadvisable (a MITM attack could jack your identity forever).

To solve this issue, OAuth2 implementations typically dole out refresh tokens alongside access tokens. A refresh token will typically have a longer expiration timeframe than an access token (anywhere between the expiration time of the access token and a month I would say). Refresh tokens are akin to a temporary user password - they do not grant any access to your API directly, however with one a user can authorize with your system via calling your OAuth2 refresh api, and get back fresh access and refresh tokens with new expiration time. This gives your application a chance to revalidate the users claims regularly (maybe their access / role has changed and they need updated claims).


JWT Tokens

Access tokens may be opaque strings that you store on the server, however I would highly recommend using JWT tokens. JWT tokens have 2 major benefits over opaque (meaningless) tokens:

1. Client Claims

The first thing you are going to need to do in your client application post-authorization is look up all kinds of stuff to build your UI. The beauty of JWT tokens is that they store all of your users claims (including your apps custom user claims) as a JSON object payload inside an encoded string which can be decoded client-side by first splitting the token on ., which breaks it into [ header, payload, sig ] base 64 encoded strings. You can then base 64 decode the payload string and run it through JSON.parse which will produce your claims key-value pairs:

const access_token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ'
const claims = JSON.parse(atob(access_token.split('.')[1]))
console.info(claims)

This allows your client application to decode the users claims atomically from nothing more than an access token vs. the traditional model of using the access token to go and look up information about the user. With JWT you will immediately know the users first name, last name, user ID, and any other data you would like to stick in the JWT token.

2. Sessionless

To use your authorized API, your client application will make requests to endpoints and send an 'Authorization': 'Bearer access_token' (where access_token is your access token). In traditional apps, the access token must be looked up server side to verify that the server granted it. The other awesome bit about JWT tokens is that when they are issued there is a server side secret that is used to sign them. When the server needs to verify them it simply uses the server side secret to sign them and if it passes, the server will grant the API request based on the claims of the decoded token. There is no need to store them server side making your architecture much simpler. The server has no need to talk to a database on every authorized API request. You will be bypassing many issues such as synchronizing access tokens across web farms or storing them at all (you will however still need to store the refresh tokens in a table linked to the user).


Cookies vs. Local Storage

A pretty common misconception people have about cookies is that they should be avoided because they open you up to CSRF attacks, however this is often not the case. Systems like web forms that send session cookies and hydrate session based on those cookies are open to CSRF attacks but if you are building a single page application and all of your security checkpoints are at your API layer, your endpoints will be checking the Authorization header for your bearer token, not the cookies. If you are doing server side rendering and using the cookies value there, you should be aware of CSRF threats and implement methods of prevention. If you go with cookies, you should ensure they do not have the HttpOnly flag set and do have the Secure flag set to protect you from MITM threats.


Since you are using node (or angular at least), I will now plug a library I wrote - jwt-autorefresh. The point of this library is simple, give it your apps refresh mechanism (the client code that makes the http request to your refresh api and subsequently stores results in a cookie) and the number of seconds that you want to have your tokens refreshed prior to their expiration, and it will handle auto scheduling refresh on your client application. Internally it decodes your JWT token and looks at its exp claim (expiration time) to figure out how far out it needs to schedule your refresh. It has features such as adding a small amount of jitter to the refresh time so that all client instances will not attempt refreshing simultaneously.

like image 125
cchamberlain Avatar answered Oct 30 '22 09:10

cchamberlain


I suggest that you have a look at the answer I made here for something that is related to authentication: Authorization method for REST API utilising Active Directory

The question is about active directory, but I focused on OAuth and how you can implement a custom OAuth authentication server with some tools like thinktecture or oauth2orize.

Once you have an Oauth authentication server (out of the box ADFS, custom thinktecture in .net, custom oauth2orize in nodeJs) you can plug anything on it as it's a standard authentication protocol. For instance, Xamarin has something to make authentication with any oauth2 server: https://components.xamarin.com/gettingstarted/xamarin.auth. And as I mention in the previous answer, any web server technology or javascript technology has something to handle OAuth2.

Don't hesitate to ask any question to get more details for any of these sujects.

like image 41
Stephane Avatar answered Oct 30 '22 08:10

Stephane


Yes, It's what I'm doing for my projects now. And It's a common pattern.

Application architecture:

[Web Applications]     <-HTTPS/TLS-> [Restful Web API]

[PC Applications]      <-HTTPS/TLS-> [Restful Web API]

[Mobile Applications]  <-HTTPS/TLS-> [Restful Web API]
                                     [Restful Web API] <-Authenticate-> [over LDAP or SQL Database]
                                     [Restful Web API] <-File Stream-> [File system/file server]

NOTES:

There are some notes would impact to your design:

  1. Manage Token life time.

    • Make sure your token have a short expired date (must be in 30 minutes or less). If token is expired (or going to be expired), then you must refresh your token (Take a look at refresh token in OAUTH2 for more detail).
    • Make sure your token be discarded after logout.
    • If end-user report that there is someone using their account without their permission. Make sure you can terminate the thief's token.(It's important in an enterprise application)
  2. Secure your token

    • Avoid storing your token in cookie. Use local storage if you can.
    • Use HTTPS instead of HTTP.
    • Each platform must uses separated token: It would be help If you plan to public your API to another developer/platform/vendor.
    • Make sure you log all your issued token history (when, and issued by whom). Imagine that your application is under attack, you don't know where the token come from. It will help you to answer: Were your private key stolen by attacker?!
  3. Secure your static resource (*.pdf, images, *.doc,...)

    • You can't secure your static resource in normal way (sending an Authorization HTTP header). Then you must send it over Cookie(which I do not encourage). So, you must generate a secured token for a static resource, this token must be alive in 5 minutes or less
like image 2
Hung Doan Avatar answered Oct 30 '22 09:10

Hung Doan


Yes, it is with particular deviation from what you described. Read about OAuth2 authentication dance, as it might involve 3rd party to authenticate client (desktop/web/native mobile) with the application server.

For instance you may want to use Facebook as your Identity provider, your application server will be Service Provider and user trying to log in will be directed to FB, where he'll be issued token that he'll use for communication with your service.

While you are at it check out JWT too, since it provides extra level of security to token auth.

Also, Auth0 even if you are not going to use them, provides nice documentation on authentication on various platforms.

like image 1
vittore Avatar answered Oct 30 '22 09:10

vittore