Welcome To Golang By Example

HTTP Client/Server with Basic Auth in Go (Golang)

Overview

Basic auth is the simplest form of providing access controls for resources on web server.  Basic Access Authentication is a way of providing user name and password to the server while making an HTTP request.  The credentials are send in the headers of the request. Below is the header and format in which credentials are send.

Authorization : Basic 
:

Basic Auth is specified in RFC 7617

https://tools.ietf.org/html/rfc7617

Basic auth doesn’t require any kind of sessions identifiers or cookies. Also since the credentials is send as bas64 encoding only so there is no encryption involved. Hence basic auth is used only with HTTPS for security reasons.

HTTP Server Basic Auth Example

Let’s first see basic auth wrt to HTTP server. net/http package of golang provides a method which is defined on the *http.Request struct which returns the username and password which is present in the incoming request’s Authorization Header. Below is the signature of the method

func (r *Request) BasicAuth() (username, password string, ok bool)

What this method does it that it checks the Authorization header and then extracts the username and password from  Base64 encoded value and return it. If there is any issue in parsing it will return ok variable as false. So while using this function, we first need to check the value of ok variable. If the ok variable is true then we can further match the username and password and verify if it is correct.

Let’s see a program for this

package main

import (
	"fmt"
	"net/http"
)

var (
	username = "abc"
	password = "123"
)

func main() {
	handler := http.HandlerFunc(handleRequest)
	http.Handle("/example", handler)
	http.ListenAndServe(":8080", nil)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {

	u, p, ok := r.BasicAuth()
	if !ok {
		fmt.Println("Error parsing basic auth")
		w.WriteHeader(401)
		return
	}
	if u != username {
		fmt.Printf("Username provided is correct: %s\n", u)
		w.WriteHeader(401)
		return
	}
	if p != password {
		fmt.Printf("Password provided is correct: %s\n", u)
		w.WriteHeader(401)
		return
	}
	fmt.Printf("Username: %s\n", u)
	fmt.Printf("Password: %s\n", p)
	w.WriteHeader(200)
	return
}

Server accepts the below username and password

For making the request we have to do Base64 encoding of  below string which is a username and password joined by a single colon(:)

abc:123

Base64 encoding of above string will be.

YWJjOjEyMw==

You can check it here – https://www.base64encode.org/

Now make the below request

curl -v -X POST http://localhost:8080/example -H "Authorization: Basic YWJjOjEyMw=="

This request will get the status code as 200. Also it will correctly print the username and password in the logs as well.

Username: abc
Password: 123

Now send the malformed Base64 encoded value.

curl -v -X POST http://localhost:8080/example -H "Authorization: Basic YWJjOjEy"

It will get the status code as 401. It will also print below in the logs

Error parsing basic auth

HTTP Client Basic Auth Example

net/http package of golang also provides a method which is defined on the *http.Request struct which can be used to set the basic auth header.  Below is the signature of the method

func (r *Request) SetBasicAuth(username, password string)

What this method does it takes in username and password and sets Authorization header with base64 encoded value of username and password joined by a single colon(:).

Let’s see a program for this

package main

import (
	"fmt"
	"net/http"
	"time"
)

var (
	username = "abc"
	password = "123"
)

func main() {
	call("https://localhost:8080/example", "POST")
}

func call(url, method string) error {
	client := &http.Client{
		Timeout: time.Second * 10,
	}
	req, err := http.NewRequest(method, url, nil)
	if err != nil {
		return fmt.Errorf("Got error %s", err.Error())
	}
	req.SetBasicAuth(username, password)
	response, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("Got error %s", err.Error())
	}
	defer response.Body.Close()
	return nil
}

In the above program we are making a call to the server which we had set up earlier. See how we set up the basic auth in the outgoing request

req.SetBasicAuth(username, password)

If you will run the above program you will get a 200 from the server which we had set up above.

Note: We are printing  username and password above just for illustration purposes. In real program they need to be kept encrypted in some secure manner.  Also we are sending a http request below and not https for basic auth. Again this was just for illustrated only and both client and server lie on the same machine. This is not recommended and basic auth should be used only with HTTPS