How to Secure Web Services with Client-Side Authentication

authenticationauthorizationdjangosamlweb-api

I have web application which structure is as-

  • webapi : django web services [NOT REST] no security implemented
  • frontend : Angular2. authentication implemented via SAML
  • Database : Mongodb

Can you please suggest best way to secure webapi, as currently anyone can access web services who has server[api] url

It will be big help if you suggest the authentication and authorization flow because I am totally stuck. Thanks in advance.

Best Answer

I'll describe two ways you can do this:

OAuth

I'd recommend you use OAuth for the web api. You do not have to replace the SAML authentication if you do not want (though it would be more consistent if you used OIDC for the application authorization).

Basically, you'd authenticate against your spring app via SAML then, when querying the web api, in the Authorization Request phase of the OAuth workflow, you'd implement the authorization server on the same server as your spring app so you can use the session context as authentication for the authorization request.

You should take a look here to get an introduction to OAuth. OAuth was designed (in part) to solve exactly this problem.

I realize this is short on OAuth details but there are lots of good examples/tutorials out there on how to do this. You just need to recognize that, in the protocol flow, your spring app would serve the role of Authorization Server and would implicitly provide Authorization Grants for the web api service for Authorization Requests originating from (SAML) authenticated clients.

Your app is what OAuth refers to as a single page app (no sever-based client). The flow for single page apps is described here. Essentially, your spring app will implement an OAuth Authorization Server, your Angular (in-browser) app will request an authorization code from your Authorization Server. If you want your user to approve access then you will create an approval page which describes what API actions they are approving. If you want this to be transparent, you would simply return the authorization code. Once your app has an authorization code, it immediately exchanges the code with the Authorization Server for an API access token.

Your Angular app would then query the API using the OAuth access token. The API receives the access token, validates that it is "good" then allows (or denies) access. You validate that the token is "good" either through a shared database with the Authorization Server (i.e. when the auth server creates a token, it stores it in the database for later validation by the API server) or by decoding a self-encoded token (basically the auth server and the api server share an encoding key and the token is an encoded string that has all the information the API needs to grant/deny access).

Roll-your-own

If OAuth is a bit too daunting (though it's arguably the Right Way to go here...) I've used a simple, home-grown authorization token scheme in the past as well.

In this case you design your web api to require an access token (provided by clients either in a header, qstring, or query payload). When authenticating the client app, your spring server will generate a token and send it back (securely via tls/ssl) to the client for use with the django web api. The token is encrypted with a shared (between the spring app and the django app) key and has a structure that the django app can grok (I usually include a timestamp to limit replay, username for local authorization, sometimes custom authorization information that the api can use instead of making local auth decisions). I'd also recommend you salt the message as well to make a plaintext attack of the token harder. Another option to limit replay is to make the tokens single use and to require a token fetch each time you make a query. And, finally, if you do use a timestamp (epoch integer seconds is convenient...) you'll need to make sure that your spring and django servers are (at least somewhat) in time sync.

Related Topic