# HTTP Basic Auth

Go menyediakan package yang dapat digunakan untuk proses HTTP basic authentication.&#x20;

Metode ini membutuhkan informasi username dan password untuk disisipkan dalam header request (dengan format tertentu) sehingga tidak memerlukan cookies maupun session. Lebih jelasnya silakan baca [RFC-7617](https://tools.ietf.org/html/rfc7617).

Data username dan password tidak langsung ditampilkan dalam header, namun data tersebut harus di-encode terlebih dahulu ke dalam format yg sudah ditentukan sesuai spesifikasi, sebelum dimasukan ke header.

Berikut adalah contoh penulisan basic auth:

```
// Request header
Authorization: Basic ZGF2aWR3aW5hbGRhOjEyMzQ1==
```

Informasi disisipkan dalam request header dengan key `Authorization`dan value adalah `Basic` spasi hasil enkripsi dari data username dan password. Data username dan password digabung dengan separator tanda titik dua (`:`), lalu di-encode dalam format encoding Base 64.

```
// Username password encryption
base64encode("davidwinalda:12345")
// Hasilnya adalah ZGF2aWR3aW5hbGRhOjEyMzQ1==
```

Golang menyediakan fungsi untuk meng-handle request basic auth dengan cukup mudah, jadi kita tidak perlu untuk memparsing header request terlebih dahulu untuk mendapatkan informasi username dan password.

### Studi Kasus

Kita akan membuat web service sederhana untuk memperlihatkan penggunaak http basic authentication.

#### Setup pada file `main.go`

Pada file `main.go` , kita akan membuat fungsi `main` yang berisi beberapa statement berikut:

```go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/student", ActionStudent)

	server := new(http.Server)
	server.Addr = ":8080"

	fmt.Println("server started at localhost:8080")
	server.ListenAndServe()
}
```

Pada fungsi di atas kita mendaftarkan 1 API endpoint `/student` yang nantinya kita akan melakukan 2 proses `GET` :

1. GET `/student` dimana akan menampilkan seluruh data `students`&#x20;
2. GET `/student?id=1` dimana akan menampilkan data student berdasarkan query string `id`

Lalu selanjutnya seperti yang kita lakukan sebelumnya untuk setup port dan server.

Kita akan membuat handler dari `ActionStudent` masih di file `main.go` yang berisi beberapa statement berikut ini:

```go
func ActionStudent(w http.ResponseWriter, r *http.Request) {
	if !Auth(w, r) {
		return
	}
	if !AllowOnlyGET(w, r) {
		return
	}

	if id := r.URL.Query().Get("id"); id != "" {
		OutputJSON(w, GetStudentById(id))
		return
	}

	OutputJSON(w, GetStudent())
}
```

Kita bisa lihat pada kode di atas bahwa ada proses pengecekan terlebih dahulu sebelum user dapat mengakses API dari `/student` yaitu fungsi `!Auth` . Kita juga membuat pengecekan dari `!AllowOnlyGET` bahwa hanya method `GET` yang bisa diproses pada endpoint ini.

Selanjutnya kita akan membuat fungsi `OutputJSON` untuk encode data ke JSON:

```go
func OutputJSON(w http.ResponseWriter, f interface{}) {
	w.Header().Set("Content-Type", "application/json")
	result, err := json.Marshal(f)

	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	w.Write(result)
}
```

#### Setup pada file `student.go`

Pada root directory buatlah 1 file baru bernama `student.go` yang masih dalam package `main` . Pada file ini kita akan membuat `struct` dari data students dan membuat fungsi yaitu `GetStudent` dan `GetStudentById` untuk nantinya dipanggil di dalam handler yang telah dibuat. Kita juga akan mengisi data secara manual pada fungsi `init`

```go
package main

var students = []*Student{}

type Student struct {
	Id       string
	Fullname string
	Age      int
	Batch    string
}

func GetStudent() []*Student {
	return students
}

func GetStudentById(id string) *Student {
	for _, each := range students {
		if each.Id == id {
			return each
		}
	}

	return nil
}

func init() {
	students = append(students, &Student{Id: "1", Fullname: "Wisma", Age: 25, Batch: "Adorable"})
	students = append(students, &Student{Id: "2", Fullname: "Yudis", Age: 22, Batch: "Brilliant"})
	students = append(students, &Student{Id: "3", Fullname: "Sukisno", Age: 35, Batch: "Creative"})
	students = append(students, &Student{Id: "4", Fullname: "Guntur", Age: 30, Batch: "Dilligent"})
}
```

#### Setup pada file `middleware.go`

Nah inilah tahapan proses authentication. Kita akan membuat 1 file lagi pada root directory bernama `middleware.go` .

Pada file ini, kita akan mendeklarasikan secara hardcode untuk data username dan password yang kita anggap telah terdaftar

```go
const USERNAME = "davidwinalda"
const PASSWORD = "12345"
```

Selanjutnya kita akan membuat fungsi `Auth` untuk proses pengecekan Authentication. Kita menggunakan fungsi bawaan dari [package](https://golang.org/pkg/net/http/#Request.BasicAuth) `http` yaitu `BasicAuth` yang akan melakukan proses decode dari header dan mengembalikan 3 data yaitu `username` , `password` , dan `ok`. `ok` akan mengembalikan status apakah request yang dilakukan valid atau tidak.

```go
func Auth(w http.ResponseWriter, r *http.Request) bool {
	username, password, ok := r.BasicAuth()

	if !ok {
		http.Error(w, "Something went wrong", http.StatusInternalServerError)
		return false
	}

	isValid := (username == USERNAME) && (password == PASSWORD)

	if !isValid {
		http.Error(w, "Authentication is failed", http.StatusInternalServerError)
		return false
	}

	return true
}
```

Jika valid maka kita bisa melakukan pengecekan untuk validasi `username` dan `password` :

```go
isValid := (username == USERNAME) && (password == PASSWORD)

	if !isValid {
		http.Error(w, "Authentication is failed", http.StatusInternalServerError)
		return false
	}
```

Selanjutnya kita akan membuat fungsi `AllowOnlyGET` untuk membatas akses endpoint hanya bisa menggunakan method `GET` :

```go
func AllowOnlyGET(w http.ResponseWriter, r *http.Request) bool {
	if r.Method != "GET" {
		http.Error(w, "Only allow GET method", http.StatusInternalServerError)
		return false
	}

	return true
}
```

Untuk kode lengkapnya bisa dilihat di bawah ini:

```go
package main

import "net/http"

const USERNAME = "davidwinalda"
const PASSWORD = "12345"

func Auth(w http.ResponseWriter, r *http.Request) bool {
	username, password, ok := r.BasicAuth()

	if !ok {
		http.Error(w, "Something went wrong", http.StatusInternalServerError)
		return false
	}

	isValid := (username == USERNAME) && (password == PASSWORD)

	if !isValid {
		http.Error(w, "Authentication is failed", http.StatusInternalServerError)
		return false
	}

	return true
}

func AllowOnlyGET(w http.ResponseWriter, r *http.Request) bool {
	if r.Method != "GET" {
		http.Error(w, "Only allow GET method", http.StatusInternalServerError)
		return false
	}

	return true
}
```

### Menjalankan Program

Untuk menjalankan program kita tidak bisa menggunakan `go run main.go` karena terdapat beberapa file sebagai package `main` . Oleh karena itu kita dapat menjalankan program dengan perintah berikut:

```
go run *.go
```

![Running program menggunakan go run \*.go](/files/-MTpdjexr-Rk4AK5eRhA)

Kita akan mencoba HTTP Authentication Basic dan mengakses API endpoint yang telah kita buat menggunakan Postman:

![Mengakses endpoint dengan http auth basic](/files/-MTpsmshwznGphDRF-8A)

Jika data authentication salah atau tidak sesuai maka pada postman akan mengembalikan data berikut:

![Credential authentication tidak sesuai](/files/-MTpt6inCvaQVBaTa7zZ)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://davidwinalda94.gitbook.io/mastering-golang/go-basic-for-web-development/http-basic-auth.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
