I'm trying to retrieve a response from a POST endpoint which accepts a payload.
For curl request:
curl --request POST \
--url https://api.io/v1/oauth/token \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{
"userToken": "myemail#domain.com:MyUserProfileToken"
}'
I can do this with:
func GetJWT() string {
endpoint := "https://api.io/v1/oauth/token"
payload := strings.NewReader(`{
"userToken":"myemail#domain.com:MyUserProfileToken"
}`)
req, _ := http.NewRequest("POST", endpoint, payload)
req.Header.Add("Accept", "application/json")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
return string(body)
}
and
payload := strings.NewReader("{\n \"userToken\": \"myemail#domain.com:MyUserProfileToken\"\n}")
However, when I try to pass string pointers for email and token, and declare the payload like
func GetJWT(userEmail, userToken *string) string {
endpoint := "https://api.io/v1/oauth/token"
payload := strings.NewReader("{\n \"userToken\": \*userEmail\":\"\*userToken\n}")
req, _ := http.NewRequest("POST", endpoint, payload)
req.Header.Add("Accept", "application/json")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
return string(body)
}
an error is returned for unknown escape (column 53 on payload declaration).
How can I escape string pointers so that I can concatenate userEmail, ":", and userToken
I see a couple problems here.
First: I think the "unknown escape" error message is caused by \* since \* is not a legitimate escape character.
Second: Golang does not support string interpolation. So the userEmail and userToken variables are actually never used in your GetJWT function.
You can format variables into a string using Sprintf from the standard library fmt package. That would look like this:
fmt.Sprintf("{\n \"userToken\" : \"%s:%s\" \n}", *userEmail, *userToken)
Related
Go here using Chi renderer for a basic REST service. I have the following structs and functions:
type Order struct {
OrderId uuid.UUID `json:"orderId",gorm:"type:uuid;primary_key;not null;default gen_random_uuid()"`
Quantity int `json:"quantity",gorm:"not null"`
Status string `json:"status",gorm:"not null"`
}
func (o *Order) Bind(r *http.Request) error {
return nil
}
func (o *Order) Render(w http.ResponseWriter, r *http.Request) error {
return nil
}
func NewOrdersList(orders []Order) []render.Renderer {
list := []render.Renderer{}
for _, order := range orders {
list = append(list, &order)
}
return list
}
func GetOrderByIdHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
orderId := chi.URLParam(r, "orderId")
order, err := fetchOrder(orderId)
if err != nil {
render.Render(w, r, NewInternalServerError(err))
return
}
log.Info("order status is " + order.Status)
render.Bind(r, &order)
return
}
}
When I run this and hit the endpoint that invokes the GetOrderByIdHandler() function, I get back a 200 OK/Success. However there is no JSON in the response body, whereas I would have expected a marshalled JSON payload representing an "order", such as:
{
"orderId": "12345",
"quantity": 1,
"status": "SENT"
}
However my curl shows nothing in the response body:
$ curl -i -H "Content-Type: application/json" -H "Accept: application/json" -X GET http://localhost:9400/myapp/v1/orders/12345
HTTP/1.1 200 OK
Vary: Origin
Date: Wed, 24 Jun 2020 07:09:30 GMT
Content-Length: 0
Any idea where I'm going awry? I do see the log statement print out the order status right before calling bind, so I know its not a null/empty order instance.
render.Bind is input-only, i.e. for decoding the request payload. Instead use render.JSON to send a json response.
func GetOrderByIdHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
orderId := chi.URLParam(r, "orderId")
order, err := fetchOrder(orderId)
if err != nil {
render.Render(w, r, NewInternalServerError(err))
return
}
log.Info("order status is " + order.Status)
render.JSON(w, r, order)
}
}
Or, alternatively, you could also use the standard approach: import the encoding/json package and then use it like so:
func GetOrderByIdHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
orderId := chi.URLParam(r, "orderId")
order, err := fetchOrder(orderId)
if err != nil {
render.Render(w, r, NewInternalServerError(err))
return
}
log.Info("order status is " + order.Status)
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(order); err != nil {
render.Render(w, r, NewInternalServerError(err))
}
}
}
Also note that the proper format for multiple struct tags is "space delimited" not "comma separated". For example: json:"quantity" gorm:"not null" is correct, while json:"quantity",gorm:"not null" is not.
I am a newbie and trying to create a Golang script that reads from one endpoint then updates some of the fields and posts to a different endpoint. The PUT request to the endpoint has this as a curl command.
curl -v \
-X PUT -H 'X-Api-Key:{Key}' \
-H 'Content-Type: application/json' url/{id} \
-d '{ "name" : "Somename", "type": "Sometype", "status" : "enabled"}'
I want to keep the same name and same type from the endpoint that I send the GET request, but I want to change status from enabled to disabled when posting to the other endpoint. So basically whatever results I get from the one endpoint will stay the same except the status that I need to change to disabled. Any example code will assist.
This is the code I have so far but it is just for reading the endpoint. So not sure how to join the two.
func main() {
req, _ := http.NewRequest("GET", "URL", nil)
req.Header.Set("X-Api-Key", <Key>)
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
var obj struct {
Library []struct {
Name string `json:"name"`
Type string `json:”type”`
Status string `json:”status"`
} `json:”library"`
}
if err := json.Unmarshal(body, &obj); err != nil {
panic(err)
}
for _, app := range obj.Library {
fmt.Println(app.Name, app.Type, app.Status)
}
}
You are almost there, just need to loop over the Library items, updating the status and doing the http put requests.
Something like this should work (not tested):
for _, item := range obj.Library {
item.Status = "disabled"
bs, err := json.Marshal(item)
// check err
req, err := http.NewRequest("PUT", "url", bytes.NewBuffer(bs))
// check err
res, err := http.DefaultClient.Do(req)
// check err
// check res.StatusCode
}
I'm trying to make a request to my (magento)webserver using golang.
I managed to make a POST request, but however, I'm not getting the same response I'm getting when using CURL from the cmd.
I followed this post (How to get JSON response in Golang) which does not give me any response.
So I tried this
package main
import (
"fmt"
"net/http"
"os"
)
var protocol = "http://"
var baseURL = protocol + "myserver.dev"
func main() {
fmt.Print("Start API Test on: " + baseURL + "\n")
r := getCart()
fmt.Print(r)
}
func getCart() *http.Response {
resp, err := http.Post(os.ExpandEnv(baseURL+"/index.php/rest/V1/guest-carts/"), "", nil)
if err != nil {
fmt.Print(err)
}
return resp
}
This just return the http reponse like
{200 OK 200 HTTP/1.1 1 1 map[Date:[Thu, 04 May 2017 05:30:20 GMT] Content-Type:[application/json; charset=utf-8] Set-Cookie:[PHPSESSID=elklkflekrlfekrlklkl; expires=Thu, 04-May-2017 ...
When using curl -g -X POST "my.dev/index.php/rest/V1/guest-carts/" I retrieve some kind of ID which I need to proceed.
How can I get the this curl result in golang?
You need to read the resp.Body (and don't forget to close it!), ie
func main() {
fmt.Print("Start API Test on: " + baseURL + "\n")
r := getCart()
defer r.Body.Close();
if _, err := io.Copy(os.Stdout, r.Body); err != nil {
fmt.Print(err)
}
}
I am trying to make a Json web token authentication system with Go however I cant seem to get the parsing of the web token working.
The error occurs in the following function.
func RequireTokenAuthentication(rw http.ResponseWriter, req *http.Request, next http.HandlerFunc) {
authBackend := InitJWTAuthenticationBackend()
jwtString := req.Header.Get("Authorization")
token, err := jwt.Parse(jwtString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
log.Println("Unexpected signing method")
return nil, fmt.Errorf("Unexpected signing method: %v", token.Header["alg"])
} else {
log.Println("The token has been successfully returned")
return authBackend.PublicKey, nil
}
})
log.Println(token)
log.Println(token.Valid)
if err == nil && token.Valid && !authBackend.IsInBlacklist(req.Header.Get("Authorization")) {
next(rw, req)
} else {
rw.WriteHeader(http.StatusUnauthorized)
log.P
rintln("Status unauthorized RequireTokenAuthentication")
}
}
returns the following log
[negroni] Started GET /test/hello
2016/09/13 01:34:46 &{Bearer eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NzM5NzQ4OTAsImlhdCI6MTQ3MzcxNTY5MCwic3ViIjoiIn0.mnwEwdR8nuvdLo_4Ie43me7iph2LeSj1uikokgD6VJB7isjFPShN8E7eQr4GKwuIiLTi34_i6iJRpmx9qrPugkzvsoxX44qlFi6M7FDhVySRiYbBQwTCvKCpvhnsK8BHJyEgy813aaxOMK6sKZJoaKs5JYUvnNZdNqmENYj1BM6FdbGP-oLHuR_CJK0Pym1NMhv9zLI1rpJOGu4mfj1t4tHYZAEGirPnzYMamtrK6TyEFE6Xi4voEEadq7hXvWREg6wNSQsYgww8uOaIWLy1yLbhTkPmT8zfRwLLYLqS_UuZ0xIaSWO1mF2plvOzz1WlF3ZEHLS31T1egB1XL4WTNQe <nil> map[] <nil> false}
2016/09/13 01:34:46 false
2016/09/13 01:34:46 Status unauthorized RequireTokenAuthentication
[negroni] Completed 401 Unauthorized in 71.628ms
and here is the cURL that I am using to initiate it
curl -H "Authorization: Bearer eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NzM5NzQ4OTAsImlhdCI6MTQ3MzcxNTY5MCwic3ViIjoiIn0.mnwEwdR8nuvdLo_4Ie43me7iph2LeSj1uikokgD6VJB7isjFPShN8E7eQr4GKwuIiLTi34_i6iJRpmx9qrPugkzvsoxX44qlFi6M7FDhVySRiYbBQwTCvKCpvhnsK8BHJyEgy813aaxOMK6sKZJoaKs5JYUvnNZdNqmENYj1BM6FdbGP-oLHuR_CJK0Pym1NMhv9zLI1rpJOGu4mfj1t4tHYZAEGirPnzYMamtrK6TyEFE6Xi4voEEadq7hXvWREg6wNSQsYgww8uOaIWLy1yLbhTkPmT8zfRwLLYLqS_UuZ0xIaSWO1mF2plvOzz1WlF3ZEHLS31T1egB1XL4WTNQe" http://localhost:5000/test/hello
I have also tried curl without Bearer
curl -H "Authorization:eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0NzM5NzQ4OTAsImlhdCI6MTQ3MzcxNTY5MCwic3ViIjoiIn0.mnwEwdR8nuvdLo_4Ie43me7iph2LeSj1uikokgD6VJB7isjFPShN8E7eQr4GKwuIiLTi34_i6iJRpmx9qrPugkzvsoxX44qlFi6M7FDhVySRiYbBQwTCvKCpvhnsK8BHJyEgy813aaxOMK6sKZJoaKs5JYUvnNZdNqmENYj1BM6FdbGP-oLHuR_CJK0Pym1NMhv9zLI1rpJOGu4mfj1t4tHYZAEGirPnzYMamtrK6TyEFE6Xi4voEEadq7hXvWREg6wNSQsYgww8uOaIWLy1yLbhTkPmT8zfRwLLYLqS_UuZ0xIaSWO1mF2plvOzz1WlF3ZEHLS31T1egB1XL4WTNQe" http://localhost:5000/test/hello
The error is occurring because the token is invalid token.Valid = false I have generated it using the following process.
Here is the router
router.HandleFunc("/token-auth", controllers.Login).Methods("POST")
Here is the login controller
func Login(w http.ResponseWriter, r *http.Request) {
requestUser := new(models.User)
decoder := json.NewDecoder(r.Body)
decoder.Decode(&requestUser)
responseStatus, token := utils.Login(requestUser) //here the util file seen below is used
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(responseStatus)
w.Write(token)
}
This is the util file
func Login(requestUser *models.User) (int, []byte) {
authBackend := authentication.InitJWTAuthenticationBackend()
if authBackend.Authenticate(requestUser) {
token, err := authBackend.GenerateToken(requestUser.UUID)
if err != nil {
return http.StatusInternalServerError, []byte("")
} else {
response, _ := json.Marshal(parameters.TokenAuthentication{token})
return http.StatusOK, response
}
}
return http.StatusUnauthorized, []byte("")
}
and here is the method used to generate the token
func (backend *JWTAuthenticationBackend) GenerateToken(userUUID string) (string, error) {
token := jwt.New(jwt.SigningMethodRS512)
claims := token.Claims.(jwt.MapClaims)
claims["exp"] = time.Now().Add(time.Hour * time.Duration(settings.Get().JWTExpirationDelta)).Unix()
claims["iat"] = time.Now().Unix()
claims["sub"] = userUUID
tokenString, err := token.SignedString(backend.privateKey)
if err != nil {
panic(err)
return "", err
}
return tokenString, nil
}
How do I fix the Token Parsing system so that the token is valid?
If you need any additional information I would be more than happy to make an edit with the respective information.
Thank
The error returned by jwt.Parse() says
tokenstring should not contain 'bearer '
So if you remove "Bearer ":
jwtString = strings.Split(jwtString, "Bearer ")[1]
you get a bit further
The token has been successfully returned
however now there's a new error:
key is of invalid type
Sorry it's not a complete answer!
key is of invalid type
type in this context is referring to the dynamic data-type in Go.
For SigningMethodRSA, the public key must be of type *rsa.PublicKey which can be constructed by calling jwt.ParseRSAPublicKeyFromPEM().
The key value returned to the parser might be created with something like:
keyStruct, _ := jwt.ParseRSAPublicKeyFromPEM(myPublicKeyString)
See:
https://github.com/dgrijalva/jwt-go#signing-methods-and-key-types
https://godoc.org/github.com/dgrijalva/jwt-go#SigningMethodRSA
https://godoc.org/github.com/dgrijalva/jwt-go#ParseRSAPublicKeyFromPEM
Related:
How to generate JWT token always through invalid key type error
So I tried something based on the example here in my code, and get no data, but no error either. The code is:
import (
"io"
"fmt"
"net/http"
"encoding/json"
)
type Credential struct {
username string `json:"username"`
password string `json:"password"`
}
func login(res http.ResponseWriter, req *http.Request) {
if req.Method == "POST" {
cred := Credential{}
err := json.NewDecoder(req.Body).Decode(&cred)
if err != nil {
panic("can't decode")
}
fmt.Println("credentials: " + cred.username + " , " + cred.password)
}
}
I test with
curl -X POST -H "Accept: application/json" --data "{\"username\":\"x\",\"password\":\"y\"}" 127.0.0.1:8000/login -i
And the server prints out:
credentials: ,
Why is there nothing in cred.username and cred.password?
golang use first character of the field to declare public or private for that struct. so change username to Username