package main

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"encoding/hex"
	"fmt"
	"log"
	"net/url"
)

// buatState menghasilkan state acak 16 byte untuk melindungi
// alur otorisasi dari CSRF.
func buatState() (string, error) {
	b := make([]byte, 16)
	if _, err := rand.Read(b); err != nil {
		return "", err
	}
	return hex.EncodeToString(b), nil
}

func main() {
	// Generator state: panjang tetap dan nilainya tidak pernah sama.
	statePertama, err := buatState()
	if err != nil {
		log.Fatal(err)
	}
	stateKedua, err := buatState()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println("panjang state    :", len(statePertama), "karakter hex")
	fmt.Println("dua state berbeda:", statePertama != stateKedua)

	// PKCE: verifier dibuat tetap agar output deterministik; produksi
	// membuat verifier acak 43-128 karakter pada setiap proses login.
	verifier := "verifier-demo-0123456789abcdefghijklmnopqrstuv"
	jumlah := sha256.Sum256([]byte(verifier))
	challenge := base64.RawURLEncoding.EncodeToString(jumlah[:])
	fmt.Println("code_verifier    :", verifier)
	fmt.Println("code_challenge   :", challenge)

	// URL otorisasi memakai state contoh; produksi menggantinya
	// dengan hasil buatState() yang tersimpan di sesi aplikasi.
	nilai := url.Values{}
	nilai.Set("response_type", "code")
	nilai.Set("client_id", "YOUR_CLIENT_ID")
	nilai.Set("redirect_uri", "https://aplikasi.example.com/callback")
	nilai.Set("scope", "openid profile")
	nilai.Set("state", "statedemotetap0123456789")
	nilai.Set("code_challenge", challenge)
	nilai.Set("code_challenge_method", "S256")

	alamat := url.URL{
		Scheme:   "https",
		Host:     "auth.example.com",
		Path:     "/authorize",
		RawQuery: nilai.Encode(),
	}
	fmt.Println()
	fmt.Println("URL otorisasi:")
	fmt.Println(alamat.String())
}
