Go Skills

Authentication and Authorization

Authentication mechanism

Definition(s):

Hardware or software-based mechanisms that force users to prove their identity before accessing data on a device.

Authentication

Is the act of validating that users are whom they claim to be.

( Confirms users are who they say they are)

This is the first step in any security process.

If a user enters the correct data, the system assumes the identity is valid and grants access.

  • One-time pins. Grant access for only one session or transaction.
  • Passwords. Usernames and passwords ****are the most common authentication factors.
  • Authentication apps. Generate security codes via an outside party that grants access.
  • Biometrics. A user presents a fingerprint or eye scan to gain access to the system.

Authorization

Is the process of giving the user permission to access a specific resource or function.

Authorization determines what resources a user can access.

Authorization always takes place after authentication.

authorization is the process of verifying what specific applications, files, and data a user has access to.

Authentication in Go

How authentication works

A client sends the authentication request to the server with the credentials.

The server validates the credentials with the database entry.

If the match is successful, it writes something called cookie ( Cookies are small pieces of text sent to your browser by a website you visit ) in the response.

This cookie will be sent back from the client in the subsequent requests to the server which is used by the servers to validate if the cookie attached is valid (on the basis of the one sent in the first place).

Sessions

session is a way to record users authentication related payload in a cookie over a period of time.

When the user logs in in by sending valid credentials, the server attaches the cookie in the response.

Then the client uses that cookie (saved in the browser or client service) to make future requests.

When a client makes a logout request by sending a API on the server, the server destroys the session in the response.

The server can also place an expiration on cookies so that the session expires after a certain time if there is no activity.

Code example

package main

import (
	"log"
	"net/http"
	"time"

	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
)

// dummy user data
var users = map[string]string{"user1": "password", "user2": "password"}

// creating a cookie session store
var store = sessions.NewCookieStore([]byte("secret_key"))

func main() {
	r := mux.NewRouter()
	r.HandleFunc("/login", loginHandler).Methods("POST")
	r.HandleFunc("/logout", logoutHandler).Methods("GET")
	r.HandleFunc("/healthcheck", healthcheck).Methods("GET")
	// modifying http import struct to add an extra property
	// of timeout (good practice)
	httpServer := &http.Server{
		Handler:      r,
		Addr:         "127.0.0.1:8000",
		WriteTimeout: 15 * time.Second,
	}
	log.Println("Server start at port 8000")
	log.Fatal(httpServer.ListenAndServe())
}

func loginHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("loginHandler")
	if r.Method != "POST" {
		http.Error(w, "Method Not Supported", http.StatusMethodNotAllowed)
		return
	}
	// ParseForm parses the raw query from the URL and updates r.Form
	err := r.ParseForm()
	if err != nil {
		http.Error(w, "Please pass the data as URL form encoded", http.StatusBadRequest)
		return
	}
	username := r.Form.Get("username")
	password := r.Form.Get("password")

	// check if user exists
	storedPassword, exists := users[username]
	if exists {
		// Get registers and returns a session for the given name and session store.
		// session.id is the name of the cookie that will be stored in the client's browser
		session, _ := store.Get(r, "session.id")
		if storedPassword == password {
			session.Values["authenticated"] = true
			// saves all sessions used during the current request
			session.Save(r, w)
		} else {
			http.Error(w, "Invalid Credentials", http.StatusUnauthorized)
		}
		log.Println("Login successfully!")
		w.Write([]byte("Login successfully!"))

	}
}

func logoutHandler(w http.ResponseWriter, r *http.Request) {
	// Get registers and returns a session for the given name and session store
	// session.id is the name of the cookie that will be stored in the client's browser
	session, _ := store.Get(r, "session.id")
	// Set the authenticated value on the session to false
	session.Values["authenticated"] = false
	session.Save(r, w)
	log.Println("Logout Successful")
	w.Write([]byte("Logout Successful"))
}

func healthcheck(w http.ResponseWriter, r *http.Request) {
	session, _ := store.Get(r, "session.id")
	authenticated := session.Values["authenticated"]
	if authenticated != nil && authenticated != false {
		w.Write([]byte("Welcome!"))
		return
	} else {
		http.Error(w, "Forbidden", http.StatusForbidden)
		return
	}
}