Securing REST API using basic Token based Approach in Grails
Posted By : Ankit Nigam | 17-Feb-2014
Hello Friends,
Today I am going to share a simple mechanism to secure the REST API which makes use of a simple 32bit randomly generated token.
Basically REST API is used to expose the Web-Services of our application to a third party using simple HTTP requests, which includes the following:
- POST method for creating a new Object on server,
- GET method for getting single/list of Objects from server,
- PUT method to update an Object on server, &
- DELETE method for deleting an Object from server.
Now as we are providing a platform to use our Web-Services over a public domian , i.e. INTERNET, we must protect it using some mechanism so that any voilation of security and/or unauthorised/unauthenticated use can be prevented.
The approach which I have used when i came across the same problem,where I need to expose the Web-Services to the Mobile Client which is a Mobile-App & require all the data which the Web-App is using but in JSON form & the condition being, only authorised personnel can access those Web-Services.
Solution:
The best solution which i preferred that time,starting from Login to acessing REST API over HTTP methods, consists of :
- Ajax based login from Mobile-App & using login authentication provided by Spring Security Plugin.This can simply be done by providing the mobile team with the below url & parameters j_username & j_password with username & password of the user
http://serverURL:port/AppName/j_spring_security_check?ajax=true
- Now the second step is to provide response on success/failure of login call.These actions are already present in LoginController & automatically called on respective success/failure of login.You can also customise the JSON response data whatever you need at the Mobile-App end but authToken is most important which you need to generate at successful login & send it.The authToken which I have used is random UUID which is best suited for this purpose.
For Success:
def ajaxSuccess() { if(springSecurityService.principal.hasProperty("id")){ def authToken def currentUser = User.get(springSecurityService.principal.id) if(currentUser.authToken == null){ authToken = UUID.randomUUID().toString() currentUser.authToken = authToken userResourceService.update(currentUser) } else authToken = currentUser.authToken render([success: true, data:[authToken:authToken, userid:currentUser.id, username:currentUser.username] as JSON) } render([success: false,message:"Sorry.User is not authenticated"] as JSON) }
For Failure :
def authfail() { String msg = '' def exception = session[WebAttributes.AUTHENTICATION_EXCEPTION] if (exception) { if (exception instanceof AccountExpiredException) { msg = g.message(code: "springSecurity.errors.login.expired") } else if (exception instanceof CredentialsExpiredException) { msg = g.message(code: "springSecurity.errors.login.passwordExpired") } else if (exception instanceof DisabledException) { msg = g.message(code: "springSecurity.errors.login.disabled") } else if (exception instanceof LockedException) { msg = g.message(code: "springSecurity.errors.login.locked") } else { msg = g.message(code: "springSecurity.errors.login.fail") } } if (springSecurityService.isAjax(request)) { // for ajax requests from Mobile-App render([success: false,message : msg] as JSON) } else { flash.message = msg redirect action: 'auth', params: params } }
- Now if the user is successfully logged in, the Mobile-App will be getting the AuthToken in response, which works as an Unique ID of an authenticated user, & needs to be send in further REST API calls to validate the identity.
- So now the most important step, to secure our REST API & restrict it to only authenticated user.For this purpose I have used the Grails Filter.
- For instance if you have created a REST API controller having name ApiController which handles the API logic you can define the filter as:
class SecurityFilters { //filter out the api calls only & check whether the token appended is valid against the User or not & render respective json def filters = { apiURLs(controller:'api', action:'*'){ before = { if(!checkValidUser(params)){ render( status:200, contentType: "application/json", text: (['success':'false','message':'You are not a valid user'] as JSON) ) return false } } } } private boolean checkValidUser(def paramsMap){ if(paramsMap.authToken != null){ def usertest = User.findByAuthToken(paramsMap.authToken) if((usertest instanceof User ) && (usertest != null)) return true } else return false } }
- In my case I have used Grails Jax-Rs plugin which itself creates the REST API's according to the configuation defined.So for filters i have used the logic to filters calls on basis of URI consisting of "/api" as:
apiURIs(uri:"/api/**")
So in this way if the authToken is valid against a User then only one can use the Web-Services over REST API else he will be getting error message in return.This authToken can also be used further to differentiate the data for that particular user , which is to be send as the response of the REST API call.
If you have any queries or suggestion regarding this mechanism/approach feel free to comment.
Thanks,
Ankit
Request for Proposal
Cookies are important to the proper functioning of a site. To improve your experience, we use cookies to remember log-in details and provide secure log-in, collect statistics to optimize site functionality, and deliver content tailored to your interests. Click Agree and Proceed to accept cookies and go directly to the site or click on View Cookie Settings to see detailed descriptions of the types of cookies and choose whether to accept certain cookies while on the site.
About Author
Ankit Nigam
Ankit has worked on development of various SaaS applications using Grails technologies. He has good exposure on FFMPEG and video content management applications. Ankit likes mobile gaming and going out with friends.