I have the following code. I am creating a json web token (using golang-jwt) with custom claims. The issue is that when I sign the token with a key (method = HS256) and then parse the token the claims are getting changed. What mistake I am making.
Code:
package main
import (
"fmt"
"time"
"github.com/golang-jwt/jwt/v4"
)
type MyCustomClaims struct {
userid int
jwt.RegisteredClaims
}
func (app *Config) generateJWT(userid int) {
//Code to generate jwt
jt := jwt.NewWithClaims(jwt.SigningMethodHS256, MyCustomClaims{
userid,
jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(3 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
},
})
fmt.Println("What was put", jt.Claims.(MyCustomClaims).userid)
token, _ := jt.SignedString(app.secret)
//Code to check whether claims are retained
parsed_token, _ := jwt.ParseWithClaims(token, &MyCustomClaims{}, func(t *jwt.Token) (interface{}, error) {
return app.secret, nil
})
fmt.Println("What was parsed", parsed_token.Claims.(*MyCustomClaims).userid)
}
Output
What was put 8
What was parsed 0
You have to export the userid field (make it start with a capital letter). Unexported fields cannot be JSON encoded.
type MyCustomClaims struct {
UserID int `json:"userid"`
jwt.RegisteredClaims
}
Related
I have the following endpoint
package token
import (
"crypto/rsa"
"github.com/dhis2-sre/im-user/pkg/config"
"github.com/dhis2-sre/im-user/pkg/token/helper"
"github.com/gin-gonic/gin"
"log"
"net/http"
)
func ProvideHandler(config config.Config) Handler {
publicKey, err := config.Authentication.Keys.GetPublicKey()
if err != nil {
log.Fatalln(err)
}
return Handler{
publicKey,
}
}
type Handler struct {
publicKey *rsa.PublicKey
}
// Jwks godoc
// swagger:route GET /jwks Jwks
//
// Return a JWKS containing the public key which can be used to validate the JWT's dispensed at /signin
//
// responses:
// 200: Jwks
// 415: Error
// 500: Error
func (h *Handler) Jwks(c *gin.Context) {
jwks, err := helper.CreateJwks(h.publicKey)
if err != nil {
_ = c.Error(err)
return
}
c.JSON(http.StatusOK, jwks)
}
Along with the following swagger response definition
package token
import "github.com/lestrrat-go/jwx/jwk"
// swagger:response Jwks
type _ struct {
//in: body
_ jwk.Key
}
But when I try to generate the spec using the below command
swagger generate spec -o swagger/swagger.yaml -x swagger/sdk --scan-models
I get the following error
unsupported type "invalid type"
If I use interface{} rather than jwk.Key I can generate the spec without errors but obviously that's not the type I want
Upgrading to version v0.29.0 solved the issue
I'm nob in GO :) just try to create simple crud throw it using gin and plugin called ozzo-validation
My code:
package models
import (
validation "github.com/go-ozzo/ozzo-validation"
"gorm.io/gorm"
)
type Post struct {
gorm.Model
Name string `gorm:"type:varchar(255);"`
Desc string `gorm:"type:varchar(500);"`
}
type PostData struct {
Name string `json:"name"`
Desc string `json:"desc"`
}
func (p PostData) Validate() error {
return validation.ValidateStruct(&p,
validation.Field(&p.Name, validation.Required, validation.Length(5, 20)),
validation.Field(&p.Desc, validation.Required),
)
}
PostController:
package controllers
import (
"curd/app/models"
"fmt"
"github.com/gin-gonic/gin"
)
func Store(c *gin.Context) {
// Validate Input
var post models.PostData
err := post.Validate()
fmt.Println(err)
}
{
"name": "sdfsdfsfsdf"
}
The problem is once I submit the above JSON data from the postman the validation gives me this in terminal :
desc: cannot be blank; name: cannot be blank.
As noted in the comments, you need to decode the data from the HTTP request into the struct before you can perform validation. The validation errors you're seeing are a product of calling Validate() on a fresh instance (with zero values in every field) of your Post struct. Try this.
func Store(c *gin.Context) {
var post models.PostData
// This will infer what binder to use depending on the content-type header.
if err := c.ShouldBind(&post); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Validate Input
err := post.Validate()
fmt.Println(err)
}
I am failing to create an Access Token for the Twillio Video Product with the golang SDK
In the docs there is golang sadly not mentioned
Does anyone of you know how I can create the required access token?
The JWT package mentioned in the examples of the other languages can not be found in the Go SDK.
I found that it is just not possible to do it with the default go SDK. I did follow the instructions on https://www.twilio.com/docs/iam/access-tokens and build the JWT myself. Maybe someone will find the solution handy:
package main
import (
"encoding/json"
"fmt"
"github.com/dvsekhvalnov/jose2go"
"log"
"time"
)
func main() {
accountSid := "XXX"
keySid := "YYY"
keySecret := "ZZZ"
username := "Simon"
roomName := "SimonsRoom"
now := time.Now()
type JWTPayload struct {
Jti string `json:"jti"`
Issuer string `json:"iss"`
Subject string `json:"sub"`
CreationUnixTimestamp int64 `json:"iat"`
NotBeforeUnixTimestamp int64 `json:"nbf"`
ExpiresUnixTimestamp int64 `json:"exp"`
Grants struct {
Identity string `json:"identity"`
Video struct {
Room string `json:"room"`
} `json:"video"`
} `json:"grants"`
}
payload := JWTPayload{
Jti: fmt.Sprintf("%s-%d",keySid,now.UnixNano()),
Issuer: keySid,
Subject: accountSid,
CreationUnixTimestamp: now.Unix(),
NotBeforeUnixTimestamp: now.Unix(),
ExpiresUnixTimestamp: now.Add(23*time.Hour).Unix(),
Grants: struct {
Identity string `json:"identity"`
Video struct {
Room string `json:"room"`
} `json:"video"`
}{
Identity: username,
Video: struct {
Room string `json:"room"`
}{
Room: roomName,
},
},
}
payloadByte, err := json.Marshal(payload)
if err != nil {
log.Fatal(err)
}
token, err := jose.SignBytes(payloadByte, jose.HS256, []byte(keySecret),
jose.Header("cty", "twilio-fpa;v=1"),
jose.Header("typ", "JWT"),
jose.Header("alg", "HS256"),
)
if err != nil {
log.Fatal(err)
}
fmt.Println(token)
}
As encoding/json needs a non-nil interface to unmarshal into: how can I reliably make a (full) copy of a user-provided pointer type, store that in my User interface, and then JSON decode into that ad-hoc?
Note: the goal here is to do this 'unattended' - that is, pull the bytes from Redis/BoltDB, decode into the interface type, and then check that the GetID() method the interface defines returns a non-empty string, with request middleware.
Playground: http://play.golang.org/p/rYODiNrfWw
package main
import (
"bytes"
"encoding/json"
"fmt"
"log"
"net/http"
"os"
"time"
)
type session struct {
ID string
User User
Expires int64
}
type User interface {
GetID() string
}
type LocalUser struct {
ID string
Name string
Created time.Time
}
func (u *LocalUser) GetID() string {
return u.ID
}
type Auth struct {
key []byte
// We store an instance of userType here so we can unmarshal into it when
// deserializing from JSON (or other non-gob decoders) into *session.User.
// Attempting to unmarshal into a nil session.User would otherwise fail.
// We do this so we can unmarshal from our data-store per-request *without
// the package user having to do so manually* in the HTTP middleware. We can't
// rely on the user passing in an fresh instance of their User satisfying type.
userType User
}
func main() {
// auth is a pointer to avoid copying the struct per-request: although small
// here, it contains a 32-byte key, options fields, etc. outside of this example.
var auth = &Auth{key: []byte("abc")}
local := &LocalUser{"19313", "Matt", time.Now()}
b, _, _, err := auth.SetUser(local)
if err != nil {
log.Fatalf("SetUser: %v", err)
}
user, err := auth.GetUser(b)
if err != nil {
log.Fatalf("GetUser: %#v", err)
}
fmt.Fprintf(os.Stdout, "%v\n", user)
}
func (auth *Auth) SetUser(user User) (buf []byte, id string, expires int64, err error) {
sess := newSession(user)
// Shallow copy the user into our config. struct so we can copy and then unmarshal
// into it in our middleware without requiring the user to provide it themselves
// at the start of every request
auth.userType = user
b := bytes.NewBuffer(make([]byte, 0))
err = json.NewEncoder(b).Encode(sess)
if err != nil {
return nil, id, expires, err
}
return b.Bytes(), sess.ID, sess.Expires, err
}
func (auth *Auth) GetUser(b []byte) (User, error) {
sess := &session{}
// Another shallow copy, which means we're re-using the same auth.userType
// across requests (bad).
// Also note that we need to copy into it session.User so that encoding/json
// can unmarshal into its fields.
sess.User = auth.userType
err := json.NewDecoder(bytes.NewBuffer(b)).Decode(sess)
if err != nil {
return nil, err
}
return sess.User, err
}
func (auth *Auth) RequireAuth(h http.Handler) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
// e.g. user, err := store.Get(r, auth.store, auth.userType)
// This would require us to have a fresh instance of userType to unmarshal into
// on each request.
// Alternative might be to have:
// func (auth *Auth) RequireAuth(userType User) func(h http.Handler) http.Handler
// e.g. called like http.Handle("/monitor", RequireAuth(&LocalUser{})(SomeHandler)
// ... which is clunky and using closures like that is uncommon/non-obvious.
}
return http.HandlerFunc(fn)
}
func newSession(u User) *session {
return &session{
ID: "12345",
User: u,
Expires: time.Now().Unix() + 3600,
}
}
If you need to deep copy an interface, add that method to your interface.
type User interface {
GetID() string
Copy() User
}
type LocalUser struct {
ID string
Name string
Created time.Time
}
// Copy receives a copy of LocalUser and returns a pointer to it.
func (u LocalUser) Copy() User {
return &u
}
Because the application will decode to a User and the argument to the JSON decoder must be a pointer value, we can assume that User values are pointer values. Given this assumption, the following code can be used to create a new zero value for decoding:
uzero := reflect.New(reflect.TypeOf(u).Elem()).Interface().(User)
playground example
I am attempting to use go-http-auth with martini-go. In the example given here - https://github.com/abbot/go-http-auth
package main
import (
auth "github.com/abbot/go-http-auth"
"fmt"
"net/http"
)
func Secret(user, realm string) string {
if user == "john" {
// password is "hello"
return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1"
}
return ""
}
func handle(w http.ResponseWriter, r *auth.AuthenticatedRequest) {
fmt.Fprintf(w, "<html><body><h1>Hello, %s!</h1></body></html>", r.Username)
}
func main() {
db, err := sql.Open("postgres", "postgres://blabla:blabla#localhost/my_db")
authenticator := auth.NewBasicAuthenticator("example.com", Secret)
m := martini.Classic()
m.Map(db)
m.Get("/users", authenticator.Wrap(MyUserHandler))
m.Run()
}
The Secret function is using a hardcoded user "john".
The authentication is successful when I execute
curl --user john:hello localhost:3000/users
Obviously, this is a trivial example with hardcoded username and password.
I am now changing the Secret function to this
func Secret(user, realm string) string {
fmt.Println("Executing Secret")
var db *sql.DB
var (
username string
password string
)
err := db.QueryRow("select username, password from users where username = ?", user).Scan(&username, &password)
if err == sql.ErrNoRows {
return ""
}
if err != nil {
log.Fatal(err)
}
//if user == "john" {
//// password is "hello"
//return "$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1"
//}
//return ""
return ""
}
But it fails with PANIC: runtime error: invalid memory address or nil pointer dereference. Which is obviously because I am attempting to instantiate var db *sql.DB in the Secret function. I cannot pass db *sql.DB into the Secret function either because auth.BasicNewAuthentication is expecting a Secret argument that conforms to type func (string, string) string.
How can I implement my database query correctly and return the password for comparison?
You can use a simple closure to pass in a reference to your DB to the authenticator function:
authenticator := auth.NewBasicAuthenticator("example.com", func(user, realm string) string {
return Secret(db, user, realm)
})
…and then change your Secret to accept the database as the first argument:
func Secret(db *sql.DB, user, realm string) string {
// do your db lookup here…
}
Alternative approach to Attilas answer. You can define a struct, define the Secret() handler on it and pass only the referenced function (go keeps the reference to the "owner") into the authhandler.
type SecretDb struct {
db *DB
}
func (db *SecretDb) Secret(user, realm string) string {
// .. use db.db here
}
func main() {
secretdb = SecretDb{db}
...
auth.NewBasicAuthenticator("example.com", secretdb.Secret)
...
}