github.com/mailgun/holster/v4@v4.20.0/httpsign/README.md (about) 1 httpsign 2 ========= 3 4 Mailgun tools for signing and authenticating HTTP requests between web services. 5 6 **Overview** 7 8 An keyed-hash message authentication code (HMAC) is used to provide integrity and 9 authenticity of a message between web services. The following elements are input 10 into the HMAC. Only the items in bold are required to be passed in by the user, the 11 other elements are either optional or build by httpsign for you. 12 13 * **Shared secret**, a randomly generated number from a CSPRNG. 14 * Timestamp in epoch time (number of seconds since January 1, 1970 UTC). 15 * Nonce, a randomly generated number from a CSPRNG. 16 * **Request body.** 17 * Optionally the HTTP Verb and HTTP Request URI. 18 * Optionally an additional headers to sign. 19 20 Each request element is delimited with the character `|` and each request element is 21 preceded by its length. A simple example with only the required parameters: 22 23 ``` 24 shared_secret = '042DAD12E0BE4625AC0B2C3F7172DBA8' 25 timestamp = '1330837567' 26 nonce = '000102030405060708090a0b0c0d0e0f' 27 request_body = '{"hello": "world"}' 28 29 signature = HMAC('042DAD12E0BE4625AC0B2C3F7172DBA8', 30 '10|1330837567|32|000102030405060708090a0b0c0d0e0f|18|{"hello": "world"}') 31 ``` 32 33 The timestamp, nonce, signature, and signature version are set as headers for the 34 HTTP request to be signed. They are then verified on the receiving side by running the 35 same algorithm and verifying that the signatures match. 36 37 Note: By default the service can securely handle authenticating 5,000 requests per 38 second. If you need to authenticate more, increase the capacity of the nonce 39 cache when initializing the package. 40 41 **Examples** 42 43 44 _Signing a Request_ 45 46 ```go 47 import ( 48 "net/http" 49 "strings" 50 51 "github.com/mailgun/lemma/httpsign" 52 ) 53 54 auths := httpsign.New(&httpsign.Config{Keypath: "/path/to/file.key"}) 55 56 [...] 57 58 // build new request 59 requestBody := strings.NewReader(`{"hello":"world"}`) 60 request, _ := http.NewRequest("POST", "", requestBody) 61 62 // sign request 63 err := auths.SignRequest(request) 64 if err != nil { 65 return err 66 } 67 68 // submit request 69 client := &http.Client{} 70 response, _ := client.Do(request) 71 ``` 72 73 _Signing a Request with Headers_ 74 75 ```go 76 import ( 77 "net/http" 78 "strings" 79 80 "github.com/mailgun/lemma/httpsign" 81 ) 82 83 auths := httpsign.New(&httpsign.Config{ 84 Keypath: "/path/to/file.key", 85 HeadersToSign: []string{"X-Mailgun-Header"}, 86 }) 87 88 [...] 89 90 // build new request 91 requestBody := strings.NewReader(`{"hello":"world"}`) 92 request, _ := http.NewRequest("POST", "", requestBody) 93 request.Header.Set("X-Mailgun-Header", "foobar") 94 95 // sign request 96 err := auths.SignRequest(request) 97 if err != nil { 98 return err 99 } 100 101 // submit request 102 client := &http.Client{} 103 response, _ := client.Do(request) 104 ``` 105 106 _Signing a Request with HTTP Verb and URI_ 107 108 ```go 109 import ( 110 "net/http" 111 "strings" 112 113 "github.com/mailgun/lemma/httpsign" 114 ) 115 116 auths := httpsign.New(&httpsign.Config{ 117 Keypath: "/path/to/file.key", 118 SignVerbAndURI: true, 119 }) 120 121 [...] 122 123 // build new request 124 requestBody := strings.NewReader(`{"hello":"world"}`) 125 request, _ := http.NewRequest("POST", "", requestBody) 126 127 // sign request 128 err := auths.SignRequest(request) 129 if err != nil { 130 return err 131 } 132 133 // submit request 134 client := &http.Client{} 135 response, _ := client.Do(request) 136 ``` 137 138 _Authenticating a Request_ 139 140 ```go 141 import ( 142 "fmt" 143 "net/http" 144 "strings" 145 146 "github.com/mailgun/lemma/httpsign" 147 ) 148 149 auths := httpsign.New(&httpsign.Config{Keypath: "/path/to/file.key"}) 150 151 [...] 152 153 func handler(w http.ResponseWriter, r *http.Request) { 154 // authenticate request 155 err := auths.AuthenticateRequest(r) 156 157 // request is invalid 158 if err != nil { 159 fmt.Fprintf(w, "<p>Unable to Authenticate Request: %v</p>", err) 160 return 161 } 162 163 // valid request 164 fmt.Fprintf(w, "<p>Request Authenticated, welcome!</p>") 165 } 166 ```