package basic import ( "encoding/json" "fmt" "time" "github.com/google/uuid" "github.com/micro/go-micro/v2/auth" "github.com/micro/go-micro/v2/auth/token" "github.com/micro/go-micro/v2/store" ) // Basic implementation of token provider, backed by the store type Basic struct { store store.Store } var ( // StorePrefix to isolate tokens StorePrefix = "tokens/" ) // NewTokenProvider returns an initialized basic provider func NewTokenProvider(opts ...token.Option) token.Provider { options := token.NewOptions(opts...) if options.Store == nil { options.Store = store.DefaultStore } return &Basic{ store: options.Store, } } // Generate a token for an account func (b *Basic) Generate(subject string, opts ...token.GenerateOption) (*auth.Token, error) { options := token.NewGenerateOptions(opts...) // construct the token token := auth.Token{ Subject: subject, Type: b.String(), Token: uuid.New().String(), Created: time.Now(), Expiry: time.Now().Add(options.Expiry), Metadata: options.Metadata, Roles: options.Roles, } // marshal the account to bytes bytes, err := json.Marshal(token) if err != nil { return nil, err } // write to the store err = b.store.Write(&store.Record{ Key: fmt.Sprintf("%v%v", StorePrefix, token.Token), Value: bytes, Expiry: options.Expiry, }) if err != nil { return nil, err } // return the token return &token, nil } // Inspect a token func (b *Basic) Inspect(t string) (*auth.Token, error) { // lookup the token in the store recs, err := b.store.Read(StorePrefix + t) if err == store.ErrNotFound { return nil, token.ErrInvalidToken } else if err != nil { return nil, err } bytes := recs[0].Value // unmarshal the bytes var tok *auth.Token if err := json.Unmarshal(bytes, &tok); err != nil { return nil, err } // ensure the token hasn't expired, the store should // expire the token but we're checking again if tok.Expiry.Unix() < time.Now().Unix() { return nil, token.ErrInvalidToken } return tok, err } // String returns basic func (b *Basic) String() string { return "basic" }