User Authentication with Go and AngularJS

I want to set up an authentication system with tokens in my Go application that uses front-end AngularJS.

What I'm looking for is tips on all the steps to create a secure system. Here are my steps:

We will consider that the user record is already written in our database.

1 - user wants to log in

The user goes to the pointer to the web application, which invites him to enter.

With my app.yaml file, I declare my HTML dependency file for AngularJS front-end:

application: authtest version: 1 runtime: go api_version: go1 handlers: - url: / static_files: frontend/index.html upload: frontend/(.*\.html) - url: /js static_dir: frontend/js - url: /.* script: _go_app 

Visual:

Alt text

The code:

 <form ng-submit="signIn()" ng-controller="signInCtrl"> <input type="email" ng-model="credentials.email" placeholder="Email" name="email"> <input type="password" ng-model="credentials.password" placeholder="Password" name="password"> <input type="submit" value="Sign in"> </form> 

The user enters their credentials and clicks the Login button.

2 - Request a server

AngularJS module code:

 <script> angular.module('authtest', ['ngCookies']) .controller('signInCtrl', ['$scope', '$http', '$window', '$cookieStore', '$route', function($scope, $http, $window, $cookieStore, $route){ var credentials = {} $scope.signIn = function() { $http.post('/signin', credentials) .success(function (data, status) { if(status == 200) { if(data.Access_token){ //set cookies with tokens $cookieStore.put('access_token', data.Access_token); $cookieStore.put('refresh_token', data.Refresh_token); $route.reload(); } else { $window.alert('Wrong credentials, try again.'); } } }) .error(function (data, status) { $window.alert('error: ' + data + '(errorStatus: ' + status + ')'); }); }; }]); </script> 

The Angular module submits the form to / signin , so the Go application should handle it:

 package main import ( "net/http" "encoding/json" "fmt" ) type SignInCredentials struct { Email string Password string } type Token struct { Access_token string Refresh_token string Id_token string } func init() { //I use init() instead of main() because I'm using App Engine. http.HandleFunc("/signin", SignInHandler) } func SignInHandler (w http.ResponseWriter, r *http.Request) { decoder := json.NewDecoder(r.Body) var c SignInCredentials err := decoder.Decode(&c) if err != nil { panic() } var hashPassword = hash(c.Password) //Is it at a good level to hash it ? if isInDatabase(c.Email, hashPassword) == false { fmt.Fprintf(w, "") // Really useful ? return } var tokens Token /** * The user seems to be well stored in the database, but how * to manage my tokens ? */ response, _ := json.Marshal(tokens) fmt.Fprintf(w, string(response)) } 

Obviously, hashPassword(p string) hashes the user's password, and isInDatabase(e string, p string) is a logical value that checks whether the provided credentials are stored in our database.

  • As I said in the code, I wonder if a good moment can hash a user's password or maybe use it on the client side ?
  • Printing a line with a zero car if the user is not in the database is really useful or can I just return the function?
  • The main question is: how to manage my tokens? I often see that tokens consist mainly of access_token , refresh_token and id_token . I also know that access_token limited in time for use (current session, for example, 3600 seconds), and we use refresh_token to get a new new access_token . But how to create and save it?

3 - Handling with AngularJS

As already written in the code of the AngularJS module, when the user is well authenticated, we set cookies with the provided tokens . Is this a good way? I am also wondering how to prevent XSRF (CSRF) attacks on my system?

Thank you for your future answers and advice.

+7
angularjs authentication go token
source share
1 answer

Well, I used this approach (according to Frederick Naqstad), and so far this is normal.

Authentication is pretty simple. The user submits credentials via an encrypted connection through the form:

 <form name="loginform" class="uk-form" ng-submit="login()"> <fieldset data-uk-margin> <legend><h2>Login</h2></legend> <div class="uk-form-row"> <input class="uk-form-large" type="text" ng-model="cred.user" placeholder="Username" required> </div> <div class="uk-form-row"> <input class="uk-form-large" type="password" ng-model="cred.password" placeholder="Password" required> </div> <div class="uk-form-row"> <button ng-disabled="loginform.$invalid" class="uk-button uk-button-large" type="submit">Login</button> </div> </fieldset> </form> 

The controller then processes the response as follows:

 App.controller('LoginCtrl', function ($rootScope, $scope, $location, $window, authService) { $scope.cred = {} $scope.login = function () { if ($scope.loginform.$valid) { authService.auth(this.cred, function (stat) { if (stat === 200) { $rootScope.loginStatus = authService.isLoggedIn(); $location.path('/test'); } else { .... $location.path('/login'); } }); $scope.cred = {} $scope.loginform.$setPristine(); } }; $window.document.title = 'Admin Login'; }); 

The controller expects a 200 http status code (which the server should not respond if authentication is not successful), if the server responds with something other than 200, the route changes again to the login page.

The tricky part is checking the authentication status check.

The way I implemented my authentication system is to add user attributes to the route object (for example, a guide, but without a role system) as follows:

App.js

 ... $routeProvider.when('/login', { templateUrl: '/content/...', controller: 'Ctrl1', requireLogin: false }).when('/logout', { resolve: { logout: function ($location, $rootScope, authService) { authService.logout(function (s) { if (s === 200) { $rootScope.loginStatus = authService.isLoggedIn(); $location.path('/test'); } else { .... } }); } }, requireLogin: true }).when('/metaconfig', { templateUrl: '/content/...', controller: 'Ctrl2', requireLogin: true ... 

Then whenever a route is requested, I have this function that evaluates whether a route requires certain privileges / authentication on that route or not (ofc this does not mean that your route is protected, it just means that your average joe wont have the ability to view routes if js files do not change on the fly)

App.js

 angular.module('App', ['ngCookies', 'ngRoute']) .config(function{...}).run(function ($rootScope, ..., $location, authService) { $rootScope.loginStatus = false; authService.authCheck(); $rootScope.$on('$routeChangeStart', function (event, next, current) { if (next.requireLogin) { if (!authService.isLoggedIn()) { $location.path('/login'); event.preventDefault(); } } }); 

The function passed with $routeChangeStart calls another function inside the service, which I called authService , and looks like this:

authService.js

 'use strict'; App.service('authService', function ($rootScope, $log, $http, $q) { var userIsAuthenticated = false; this.auth = function (up, cb) { $http({method: 'POST', url: '/api/login', data: up}). success(function (data, status, headers, config) { if (status === 200) { userIsAuthenticated = true; } cb(status) }). error(function (data, status, headers, config) { userIsAuthenticated = false; cb(status) }); }; this.authCheck = function () { $http({method: 'PUT', url: '/api/login' }). success(function (data, status, headers, config) { if (status === 200) { userIsAuthenticated = true; } else { userIsAuthenticated = false; } $rootScope.loginStatus = userIsAuthenticated; }). error(function (data, status, headers, config) { userIsAuthenticated = false; $rootScope.loginStatus = userIsAuthenticated; }); }; this.isLoggedIn = function () { return userIsAuthenticated; }; this.logout = function (cb) { $http({ method: 'DELETE', url: '/api/logout' }). success(function (data, status, headers, config) { userIsAuthenticated = false; cb(status) }). error(function (data, status, headers, config) { userIsAuthenticated = false; cb(status) }); }; }); 

Now, every time a route requiring a certain role or authentication will have to evaluate and receive a status code 200 from the server, otherwise the authentication status will be false until the user is authenticated again. Finally, relying on your interface, even 1% of the authorization process, the system will be completely redundant.


Edit

CSRF Risk and Session Management

In the case of CSRF, I use a framework called Beego , this structure offers a mechanism to prevent CSRF from the box, where you just need to specify the expiration date and token encryption.

When it comes to login sessions, the server must manage the encrypted sessions, which are stored as cookies on the client side, of course, I do not recommend you implement this, because it is very risky and may be implemented incorrectly. Again, Beego offers a nice feature that allows you to manage and encrypt sessions in your own way.

Hope this helps answer your question, good luck.

+2
source share

All Articles