Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions hash/const.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Copyright © 2025 Prabhjot Singh Sethi, All Rights reserved
// Author: Prabhjot Singh Sethi <prabhjot.sethi@gmail.com>

package hash

// Constants for HTTP authentication header keys used in HMAC-based signing and validation.
const (
apiKeySignatureHeader = "x-signature" // Header for the HMAC-SHA256 signature
apiKeyTimestampHeader = "x-timestamp" // Header for the request timestamp (RFC3339 format)
apiKeyIdHeader = "x-api-key-id" // Header for the API key identifier
)
8 changes: 4 additions & 4 deletions hash/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ Signing HTTP Requests:
// Returns the HMAC as a byte slice (not hex-encoded).
func generateSHA256HMAC(secret string, v ...string) []byte {
// Concatenate all input strings into a single string
raw := strings.Join(v, "")
raw := strings.Join(v, "\n")

// Create a new HMAC hasher using SHA-256 and the provided secret key
h := hmac.New(sha256.New, []byte(secret))
Expand Down Expand Up @@ -135,13 +135,13 @@ func (g *generator) AddAuthHeaders(r *http.Request) *http.Request {
sig := GenerateSHA256HMAC(g.secret, r.Method, r.URL.Path, timeStamp)

// Add the computed signature to the request headers
r.Header.Add("x-signature", sig)
r.Header.Add(apiKeySignatureHeader, sig)

// Add the API key ID to the request headers
r.Header.Add("x-api-key-id", g.id)
r.Header.Add(apiKeyIdHeader, g.id)

// add timestamp to header
r.Header.Add("x-timestamp", timeStamp)
r.Header.Add(apiKeyTimestampHeader, timeStamp)
return r
}

Expand Down
2 changes: 1 addition & 1 deletion hash/generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func Test_HashGeneration(t *testing.T) {

sig := GenerateSHA256HMAC(secret, method, path, timestamp)

if sig != "2c269d572fbd6b324b5f6eb1cf06bed60811b43a82642d5f7f438b65160caa08" {
if sig != "04a41d00f2f133c8746d11c7d3d5bfc547fc514b583e3798b1df2c9c09204461" {
t.Errorf("generated HMAC signature doesn't match as expected")
}
}
6 changes: 3 additions & 3 deletions hash/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func (v *validator) Validate(r *http.Request, secret string) (bool, error) {
}

// Retrieve the signature from the header
sigStr := r.Header.Get("x-signature")
sigStr := r.Header.Get(apiKeySignatureHeader)
if sigStr == "" {
return false, fmt.Errorf("missing signature header")
}
Expand All @@ -107,7 +107,7 @@ func (v *validator) Validate(r *http.Request, secret string) (bool, error) {
}

// Retrieve the timestamp from the header
timeStr := r.Header.Get("x-timestamp")
timeStr := r.Header.Get(apiKeyTimestampHeader)
if timeStr == "" {
return false, fmt.Errorf("missing timestamp header")
}
Expand All @@ -133,7 +133,7 @@ func (v *validator) Validate(r *http.Request, secret string) (bool, error) {
}

func (v *validator) GetKeyId(r *http.Request) string {
return r.Header.Get("x-api-key-id")
return r.Header.Get(apiKeyIdHeader)
}

// NewValidator creates a new Validator instance for validating HTTP requests.
Expand Down