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.
Is this a common pattern?
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).
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).
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.
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.
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:
Manage Token life time.
refresh token
in OAUTH2 for more detail).Secure your token
Were your private key stolen by attacker?!
Secure your static resource (*.pdf, images, *.doc,...)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With