I am using auth0 and golang for a rest service that is similar implemented as shown here.
I wonder how I can find out the name of the user that is currently triggering a certain API call - for instance if someone requests http://localhost:3000/products - the go handler in this case looks like this:
var ProductsHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
payload, _ := json.Marshal(products)
w.Header().Set("Content-Type", "application/json")
w.Write([]byte(payload))
})
Does the request r contain more information about the current user?
Or do I need to find out the current user in the middleware authentication:
func authMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
secret := []byte("{YOUR-AUTH0-API-SECRET}")
secretProvider := auth0.NewKeyProvider(secret)
audience := "{YOUR-AUTH0-API-AUDIENCE}"
configuration := auth0.NewConfiguration(secretProvider, audience, "https://{YOUR-AUTH0-DOMAIN}.auth0.com/", jose.HS256)
validator := auth0.NewValidator(configuration)
token, err := validator.ValidateRequest(r)
if err != nil {
fmt.Println(err)
fmt.Println("Token is not valid:", token)
w.WriteHeader(http.StatusUnauthorized)
w.Write([]byte("Unauthorized"))
} else {
next.ServeHTTP(w, r)
}
})
}
Does the token contain more information about the user?
I am a bit lost here. auth0 works perfectly to ensure that only registered persons can use the REST-API, but I want to deliver user specific information. So it depends on the current user what a REST call is handing back. Initially, I was thinking that auth0 would take care of this. Is there a simple way to achieve this?
Yes, you need to use token to get information about request issue.
To sort all you want you need to take a look to next:
Check out how token extracted in this method: token extraction
And the Claims here: Claims structure
And how combine it here: retrieve Claims
The claims have a field
Issuer string `json:"iss,omitempty"`
you are interested in.
Related
I am trying to create a route for GET request with the username parameter. After sending the request from postman as localhost:9090/user/?username=abc I am unable to get the response. It is showing 404 error.
func main() {
router := gin.Default()
router.POST("/user", controllers.CreateUser)
router.GET("/user/:username", GetUser)
router.HEAD("/user/:username", controllers.GetUserMeta)
router.Run("localhost:9090")
}
func GetUser(context *gin.Context) {
// get specific record from database
uname := context.Param("username")
fmt.Println("received:", uname)
//context.IndentedJSON(http.StatusOK, user)
}
I am wondering why the GetUser method is not executed.
With a single API resource /, we have written only one handler that process GET & POST request on API resource /
POST we use to create a resource in database, byt sending data in request body
PUT we use to update an existing resource in database
My understanding is, RESTful best practice says, a handler need to serve an API resource(say /) for all requests GET, POST & PUT
We want the same handler to process PUT request, but the API resource will be something like /1234, where 1234 is existing id
Technically, API resource /1234 will also map to same handler that processes /, but,
From RESTful best practices, Does /1234 need to be handled without passing id as part of API resource URI? something like below...
func ServeHTTP(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodGet { // for API resource '/'
p.getProducts(w, r)
return
}
if r.Method == http.MethodPost { // for API resource '/'
p.addProduct(w, r)
return
}
if r.Method == http.MethodPut { // for API resource '/'
p.updateProduct(w, r)
return
}
}
func updateProduct(w http.ResponseWriter, r *http.Request) {
var idString string
decoder := json.NewDecoder(r.Body)
decoder.Decode(idString)
id, err := findID(idString)
// do whatever with id
}
func findID(str string) (int, error) {
dfa := regexp.MustCompile(`/([0-9]+)`)
matches := dfa.FindAllStringSubmatch(str, -1) // returns [][]string
idString := matches[0][1]
id, err := strconv.Atoi(idString)
return id, nil
}
As I understood right you right.
You have two call which can be handle without Id for end point /.
One is POST when the back-end with generate you Id as a result.
Second is GET for all resources but this is up to you. Maybe because of secure reason you would not like to list all available resources.
One extra information is that PUT & 'POST' can use the same handler but logic in handler has to check if 'id' is provided and do extra more logic to create resource.
I have been using the mgo driver for a while, but now its my first time having to write a fully tested REST API with it.
Here it my goal
GET /users - Retrieves a list of users
GET /users/12 - Retrieves a specific users
POST /users - Creates a new user
PUT /users/12 - Updates user #12
PATCH /users/12 - Partially updates user #12
DELETE /users/12 - Deletes user #12
My problems arise from the PATCH/PUT method. Here its what I have so far
dao := daos.NewUserCollection(r)
userRequest, err := dao.GetUserRequest(r)
found, err := dao.GetByID(mux.Vars(r)["id"])
err = dao.Patch(mux.Vars(r)["id"],userRequest)
updated, err := dao.GetByID(mux.Vars(r)["id"])
log.Println("##################################################")
log.Println("URL PARAMETER", mux.Vars(r)["id"])
log.Println("USER FROM BODY",util.Marshall(userRequest))
log.Println("USER FROM DB",util.Marshall(found))
log.Println("UPDATED USER FROM DB",util.Marshall(updated))
log.Println("##################################################")
I am getting the user like
func (c *UserCollection) GetByID(id string) (models.User, error) {
result := models.User{}
err := c.FindId(bson.ObjectIdHex(id)).One(&result)
return result, err
}
I am doing the patching like
func (c *UserCollection) Patch(selector string, user models.User) ( error) {
err := c.UpdateId(bson.ObjectIdHex(selector),user)
return err
}
But the logs show me an unwanted behaviour
2016/09/28 14:10:57 ##################################################
2016/09/28 14:10:57 URL PARAMETER 57ebf9a1926bbc5bd0e666d9
2016/09/28 14:10:57 USER FROM BODY {"id":"57ebf9a1926bbc5bd0e666d9","username":"Snarlripple","email":"Slavefair#confirmed.com","password":"password","role":"","devices":["POWERDEVICE"],"confirmed":false,"notification":false}
2016/09/28 14:10:57 USER FROM DB {"id":"57ebf9a1926bbc5bd0e666d9","username":"Snarlripple","email":"Slavefair#confirmed.com","password":"$2a$04$gWErsTOWohjoJNON8l0O8OBQU0zHesFxS2vtgcqrOzcbwCEvxfUC.","role":"user","devices":[],"confirmed":true,"notification":false}
2016/09/28 14:10:57 UPDATED USER FROM DB {"id":"57ebf9a1926bbc5bd0e666d9","username":"Snarlripple","email":"Slavefair#confirmed.com","password":"password","role":"","devices":["POWERDEVICE"],"confirmed":false,"notification":false}
2016/09/28 14:10:57 ##################################################
The api is changing the password and the role of the user. I do not want my clients to be able to do this. I want to make it so there are just a few fields it has Whats the idiomatic way of doing this?
UPDATE
I got it to work with the below. Not sure if it the best way, but works.
func (c *UserCollection) Patch(id string, user User) error {
coolmap := structs.Map(&user)
setBSON := bson.M{}
for key, value := range coolmap{
if !contains([]string{"ID","Role", "Password", "Devices"},key) {
setBSON[strings.ToLower(key)] =value
}
}
changes := bson.M{"$set": setBSON }
err := c.UpdateId(bson.ObjectIdHex(id),changes)
return err
}
func contains(s []string, e string) bool {
for _, a := range s {
if a == e {
return true
}
}
return false
}
I am interested in dynamically taking arguments from the user as input through a browser or a CLI to pass in those parameters to the REST API call and hence construct the URL dynamically using Go which is going to ultimately fetch me some JSON data.
I want to know some techniques in Go which could help me do that. One ideal way I thought was to use a map and populate it with arguments keys and corresponding values and iterate over it and append it to the URL string. But when it comes to dynamically taking the arguments and populating the map, I am not very sure how to do that in Go. Can someone help me out with some code snippet in Go?
Request example:
http://<IP>:port?api=fetchJsonData&arg1=val1&arg2=val2&arg3=val3.....&argn=valn
There's already url.URL that handles that kind of things for you.
For http handlers (incoming requests) it's a part of http.Request (access it with req.URL.Query()).
A very good example from the official docs:
u, err := url.Parse("http://bing.com/search?q=dotnet")
if err != nil {
log.Fatal(err)
}
u.Scheme = "https"
u.Host = "google.com"
q := u.Query()
q.Set("q", "golang")
u.RawQuery = q.Encode()
fmt.Println(u)
https://github.com/golang/go/issues/17340#issuecomment-251537687
https://play.golang.org/p/XUctl_odTSb
package main
import (
"fmt"
"net/url"
)
func someURL() string {
url := url.URL{
Scheme: "https",
Host: "example.com",
}
return url.String()
}
func main() {
fmt.Println(someURL())
}
returns:
https://example.com
url.Values{} provides an interface for building query params. You can construct inline and/or use .Add for dynamic properties:
queryParams := url.Values{
"checkin": {request.CheckIn},
"checkout": {request.CheckOut},
}
if request.ReservationId {
queryParams.Add("reservationId", request.ReservationId)
}
url := "https://api.example?" + queryParams.Encode() // checkin=...&checkout=...
I've unsuccessfully tried to access the Soundcloud API with Go. For any language that isn't directly support by Soundcloud, their API is very convoluted. If anyone has any resources or code examples, I'd appreciate it if someone shared them with me.
My code is as follows:
func main() {
v := url.Values{}
v.Set("scope", "non-expiring")
v.Set("client_id", auth.ClientID)
v.Set("response_type", "code")
v.Set("redirect_uri", auth.RedirectURI)
c.AuthURL = AuthEndpoint + "?" + v.Encode()
c.Values = v.Encode()
res := c.Request("POST", url.Values{})
}
func (c *Client) Request(method string, params url.Values) []byte {
params.Set("client_id", "*************")
reqUrl := "https://api.soundcloud.com/oauth2/token"
req, _ := http.NewRequest(method, reqUrl, strings.NewReader(c.Values))
req.Header.Add("Accept", "application/json")
resp, _ := c.client.Do(req)
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
return body
}
i'm active developing a package in go to access/work with Soundcloud API, it has OAuth2 support, and is already usable.
I invite you to look for it. https://github.com/njasm/gosoundcloud
Take in consideration that the package is still under heavy development, the API might change in the future.
You can have a look at yanatan16/golang-soundcloud, even though then authentication part isn't implemented yet (see issues)
There is an oauth class though.
Ad quite a few other calls to the API, for getting SoundCloud objects.