pemrograman

13 Membuat Middleware Authentication Menggunakan Oauth Pada Golang

Di dunia pemrograman modern, keamanan aplikasi menjadi hal yang sangat penting, terutama ketika melibatkan otentikasi pengguna. Salah satu metode otentikasi yang banyak digunakan saat ini adalah OAuth 2.0, yang memungkinkan aplikasi untuk mengakses sumber daya pengguna tanpa membagikan kredensial mereka. Dalam artikel ini, kita akan membahas bagaimana cara membuat middleware otentikasi menggunakan OAuth 2.0 dengan menggunakan Go dan library httprouter.

Apa itu OAuth 2.0?

OAuth 2.0 adalah protokol otentikasi dan otorisasi yang memungkinkan aplikasi pihak ketiga untuk mendapatkan akses terbatas ke sumber daya pengguna tanpa membagikan informasi kredensial pengguna. Protokol ini banyak digunakan di layanan besar seperti Google, Facebook, dan GitHub untuk memungkinkan login pengguna menggunakan akun yang sudah ada.

Dalam implementasi ini, pengguna akan diajak untuk login melalui penyedia otentikasi (seperti Google atau GitHub), dan aplikasi kita akan mendapatkan token akses yang memungkinkan akses ke data pengguna.

Mengapa Menggunakan httprouter?

Library httprouter adalah router HTTP yang cepat dan ringan untuk aplikasi Go. Router ini sangat cocok digunakan dalam aplikasi Go karena performanya yang tinggi dan cara penggunaannya yang sederhana. Dengan httprouter, kita dapat menangani permintaan HTTP dengan sangat efisien.

Pada artikel ini, kita akan memanfaatkan httprouter untuk membuat middleware otentikasi OAuth 2.0.

Persyaratan

Sebelum memulai, pastikan Anda memiliki beberapa hal berikut:

  1. Go: Pastikan Anda telah menginstal Go pada sistem Anda.
  2. Library httprouter: Kita akan menggunakan library ini untuk menangani rute HTTP.
  3. OAuth 2.0: Anda perlu mendaftar aplikasi pada penyedia OAuth (seperti Google atau GitHub) untuk mendapatkan kredensial klien (client ID dan client secret).

Instalasi httprouter:

go get github.com/julienschmidt/httprouter

1. Menyiapkan Environment OAuth 2.0

Langkah pertama adalah membuat aplikasi di penyedia OAuth 2.0 yang Anda pilih (misalnya, Google). Anda perlu mendapatkan client ID dan client secret dari penyedia tersebut.

Jika Anda memilih Google, Anda dapat melakukannya dengan mengunjungi Google Developers Console dan membuat proyek baru. Setelah itu, buat kredensial OAuth 2.0 dan simpan client ID dan client secret.

2. Menggunakan Library OAuth 2.0 untuk Go

Go memiliki beberapa library untuk bekerja dengan OAuth 2.0. Salah satu yang paling populer adalah golang.org/x/oauth2.

Untuk menginstal library ini, jalankan perintah berikut:

go get golang.org/x/oauth2
go get golang.org/x/oauth2/google

3. Membuat Middleware Authentication

Sekarang kita akan membuat middleware yang akan memeriksa token akses OAuth 2.0 dalam setiap permintaan HTTP. Jika token valid, permintaan diteruskan; jika tidak, akan mengarahkan pengguna untuk login terlebih dahulu.

Berikut adalah contoh implementasi middleware otentikasi menggunakan OAuth 2.0:

package main

import (
    "fmt"
    "log"
    "net/http"

    "github.com/julienschmidt/httprouter"
    "golang.org/x/oauth2"
    "golang.org/x/oauth2/google"
)

var oauth2Config oauth2.Config

// OAuth2 middleware to check for valid token
func oauth2Middleware(next httprouter.Handle) httprouter.Handle {
    return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
        token, err := oauth2Config.TokenSource(r.Context()).Token()
        if err != nil || !token.Valid() {
            http.Redirect(w, r, oauth2Config.AuthCodeURL("", oauth2.AccessTypeOffline), http.StatusFound)
            return
        }
        next(w, r, ps)
    }
}

// HomeHandler that will be protected by OAuth2 middleware
func homeHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    fmt.Fprintf(w, "Welcome, you are authenticated!")
}

func main() {
    oauth2Config = oauth2.Config{
        ClientID:     "YOUR_CLIENT_ID",
        ClientSecret: "YOUR_CLIENT_SECRET",
        RedirectURL:  "http://localhost:8080/callback",
        Scopes:       []string{"openid", "profile", "email"},
        Endpoint:     google.Endpoint,
    }

    router := httprouter.New()

    // Protect /home route with OAuth2 middleware
    router.GET("/home", oauth2Middleware(homeHandler))

    log.Println("Starting server on :8080")
    log.Fatal(http.ListenAndServe(":8080", router))
}

Penjelasan Kode

  • oauth2.Config: Menyimpan konfigurasi OAuth 2.0, termasuk clientID, clientSecret, dan redirectURL.
  • oauth2Middleware: Middleware ini memeriksa apakah token OAuth 2.0 yang diteruskan bersama permintaan valid. Jika tidak valid, pengguna akan diarahkan untuk login.
  • homeHandler: Handler untuk route /home, yang hanya dapat diakses jika pengguna telah berhasil diautentikasi.

4. Menambahkan Route Callback

Setelah pengguna berhasil login, penyedia OAuth 2.0 akan mengalihkan mereka kembali ke aplikasi Anda ke URL callback yang telah Anda tentukan dalam konfigurasi (RedirectURL). Berikut adalah handler untuk menangani callback:

func callbackHandler(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
    code := r.URL.Query().Get("code")
    token, err := oauth2Config.Exchange(r.Context(), code)
    if err != nil {
        http.Error(w, "Failed to get token: "+err.Error(), http.StatusInternalServerError)
        return
    }

    // Save token in session or context for future requests
    fmt.Fprintf(w, "You are authenticated! Token: %s", token.AccessToken)
}

Jangan lupa untuk menambahkan route untuk callback:

router.GET("/callback", callbackHandler)

5. Menambahkan Unit Test

Berikut adalah unit test untuk oauth2Middleware dan callbackHandler, yang memastikan bahwa middleware berfungsi dengan benar:

package main

import (
    "net/http"
    "net/http/httptest"
    "testing"
    "github.com/stretchr/testify/assert"
)

func TestOauth2Middleware(t *testing.T) {
    // Setup fake OAuth2 config (biasanya Anda akan menggunakan mock token)
    oauth2Config = oauth2.Config{
        ClientID:     "YOUR_CLIENT_ID",
        ClientSecret: "YOUR_CLIENT_SECRET",
        RedirectURL:  "http://localhost:8080/callback",
        Scopes:       []string{"openid", "profile", "email"},
        Endpoint:     google.Endpoint,
    }

    // Create a mock request
    req, err := http.NewRequest("GET", "/home", nil)
    if err != nil {
        t.Fatal(err)
    }

    // Create a mock ResponseRecorder to record the response
    rr := httptest.NewRecorder()

    // Mock token source untuk OAuth 2.0
    token := &oauth2.Token{AccessToken: "fake-access-token", TokenType: "bearer"}
    oauth2Config.TokenSource = func(ctx context.Context) oauth2.TokenSource {
        return oauth2.StaticTokenSource(token)
    }

    // Mock handler untuk route /home
    handler := oauth2Middleware(func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
        w.WriteHeader(http.StatusOK)
        w.Write([]byte("Authenticated"))
    })

    // Call the handler using the mock request and response recorder
    handler(rr, req, nil)

    // Assert that the status code is 200 OK, karena token dianggap valid
    assert.Equal(t, http.StatusOK, rr.Code)
    assert.Equal(t, "Authenticated", rr.Body.String())
}

func TestCallbackHandler(t *testing.T) {
    // Setup fake OAuth2 config dengan client ID dan client secret yang benar
    oauth2Config = oauth2.Config{
        ClientID:     "YOUR_CLIENT_ID",
        ClientSecret: "YOUR_CLIENT_SECRET",
        RedirectURL:  "http://localhost:8080/callback",
        Scopes:       []string{"openid", "profile", "email"},
        Endpoint:     google.Endpoint,
    }

    // Create a mock request to simulate the callback with an authorization code
    req, err := http.NewRequest("GET", "/callback?code=fake-auth-code", nil)
    if err != nil {
        t.Fatal(err)
    }

    // Create a mock ResponseRecorder to record the response
    rr := httptest.NewRecorder()

    // Mock the Exchange method untuk menukar kode dengan token
    oauth2Config.Exchange = func(ctx context.Context, code string) (*oauth2.Token, error) {
        return &oauth2.Token{AccessToken: "fake-access-token", TokenType: "bearer"}, nil
    }

    // Call the callbackHandler
    callbackHandler(rr, req, nil)

    // Assert that the status code is 200 OK, dan token yang diterima benar
    assert.Equal(t, http.StatusOK, rr.Code)
    assert.Contains(t, rr.Body.String(), "You are authenticated! Token: fake-access-token")
}

Untuk menjalankan unit test:

go test -v

Kesimpulan

Membuat middleware otentikasi menggunakan OAuth 2.0 dengan Go dan httprouter adalah cara yang efektif untuk mengamankan aplikasi Anda dan memberikan akses kepada pengguna yang sudah terautentikasi. Dengan mengikuti tutorial ini, Anda telah mempelajari bagaimana cara menyiapkan OAuth 2.0, membuat middleware, serta melindungi rute di aplikasi Go Anda.

Untuk lebih banyak tutorial terkait Go, Anda dapat mengunjungi Tutorial Golang.

Juga, jika Anda tertarik untuk mempelajari lebih lanjut tentang routing HTTP di Go, silakan baca Web HTTP Router pada Golang.

comments powered by Disqus