I'm trying to set a MS Teams outgoing webhook with golang & Google App Engine (deployed with gcloud app deploy
):
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
)
var secret string = "THIS_IS_A_SECRET"
func handleWebhook(w http.ResponseWriter, r *http.Request) {
fmt.Println("Webhook endpoint hit")
body, err := io.ReadAll(r.Body)
if err != nil {
http.Error(w, "Can't read request body", http.StatusBadRequest)
return
}
fmt.Println("Received webhook request:", string(body))
// Log the request body for debugging
fmt.Printf("Request Body: %s\n", string(body))
// Generate HMAC token from the request body
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(body)
expectedMAC := mac.Sum(nil)
expectedMACBase64 := base64.StdEncoding.EncodeToString(expectedMAC)
// Get the HMAC token from the request header
authHeader := r.Header.Get("Authorization")
if !strings.HasPrefix(authHeader, "HMAC ") {
fmt.Println("Invalid Authorization header")
http.Error(w, "Invalid Authorization header", http.StatusUnauthorized)
return
}
providedMACBase64 := strings.TrimPrefix(authHeader, "HMAC ")
// Compare the generated HMAC token with the provided one
if !hmac.Equal([]byte(providedMACBase64), []byte(expectedMACBase64)) {
fmt.Println("Invalid HMAC token")
fmt.Println("Expected HMAC token:", expectedMACBase64)
fmt.Println("Provided HMAC token:", providedMACBase64)
http.Error(w, "Invalid HMAC token", http.StatusUnauthorized)
return
} else {
fmt.Println("Authenticated: Valid HMAC token")
}
// Create a response in the format expected by Microsoft Teams
response := map[string]string{
"type": "message",
"text": "Webhook received successfully",
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(response)
}
func main() {
http.HandleFunc("/teams-webhook", handleWebhook)
http.ListenAndServe(":8080", nil)
}
However, the expected HMAC and provided HMAC are always different. I think there must be something wrong with my HMAC algorithm. Anyone knows what's wrong here?
For reference: I'm following the guide on https://learn.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/add-outgoing-webhook?tabs=verifyhmactoken%2Cdotnet
OK... it turns out that I forgot to decode the Base64 encoded key:
[]byte(secret)
> base64.StdEncoding.DecodeString(secret)