func (p *Policy) Verify(str string) (*Key, error) {
	var key Key
	err := p.Notary.Verify(&key, str)
	if err != nil {
		return nil, err
	}
	return &key, nil
}
Verify will verify the presented token and return the decoded raw key.
package flame
import (
	"context"
	"net/http"
	"time"
	"github.com/256dpi/oauth2/v2"
	"github.com/256dpi/xo"
	"go.mongodb.org/mongo-driver/bson"
	"github.com/256dpi/fire/heat"
	"github.com/256dpi/fire/stick"
)
var ErrInvalidFilter = xo.BF("invalid filter")
var ErrInvalidRedirectURI = xo.BF("invalid redirect uri")
var ErrGrantRejected = xo.BF("grant rejected")
var ErrApprovalRejected = xo.BF("approval rejected")
var ErrInvalidScope = xo.BF("invalid scope")
type Key struct {
	heat.Base `json:"-" heat:"fire/flame.key,1h"`
	Extra stick.Map `json:"extra,omitempty"`
	stick.NoValidation `json:"-"`
}
type Grants struct {
	Password          bool
	ClientCredentials bool
	Implicit          bool
	AuthorizationCode bool
	RefreshToken      bool
}
type Context struct {
	context.Context
	Request *http.Request
	Tracer *xo.Tracer
	writer http.ResponseWriter
	grants Grants
}
type Policy struct {
	Notary *heat.Notary
	Token GenericToken
	Clients []Client
	Grants func(ctx *Context, c Client) (Grants, error)
	ClientFilter func(ctx *Context, c Client) (bson.M, error)
	RedirectURIValidator func(ctx *Context, c Client, redirectURI string) (string, error)
	ResourceOwners func(ctx *Context, c Client) ([]ResourceOwner, error)
	ResourceOwnerFilter func(ctx *Context, c Client, ro ResourceOwner) (bson.M, error)
	GrantStrategy func(ctx *Context, c Client, ro ResourceOwner, scope oauth2.Scope) (oauth2.Scope, error)
	ApprovalURL func(ctx *Context, c Client) (string, error)
	ApproveStrategy func(ctx *Context, c Client, ro ResourceOwner, token GenericToken, scope oauth2.Scope) (oauth2.Scope, error)
	TokenData func(c Client, ro ResourceOwner, token GenericToken) map[string]interface{}
	AccessTokenLifespan       time.Duration
	RefreshTokenLifespan      time.Duration
	AuthorizationCodeLifespan time.Duration
}
func StaticGrants(password, clientCredentials, implicit, authorizationCode, refreshToken bool) func(*Context, Client) (Grants, error) {
	return func(*Context, Client) (Grants, error) {
		return Grants{
			Password:          password,
			ClientCredentials: clientCredentials,
			Implicit:          implicit,
			AuthorizationCode: authorizationCode,
			RefreshToken:      refreshToken,
		}, nil
	}
}
func DefaultRedirectURIValidator(_ *Context, client Client, uri string) (string, error) {
	if client.ValidRedirectURI(uri) {
		return uri, nil
	}
	return "", ErrInvalidRedirectURI.Wrap()
}
func DefaultGrantStrategy(_ *Context, _ Client, _ ResourceOwner, scope oauth2.Scope) (oauth2.Scope, error) {
	if !scope.Empty() {
		return nil, ErrInvalidScope.Wrap()
	}
	return scope, nil
}
func StaticApprovalURL(url string) func(*Context, Client) (string, error) {
	return func(*Context, Client) (string, error) {
		return url, nil
	}
}
func DefaultApproveStrategy(*Context, Client, ResourceOwner, GenericToken, oauth2.Scope) (oauth2.Scope, error) {
	return nil, ErrApprovalRejected.Wrap()
}
func DefaultTokenData(_ Client, ro ResourceOwner, _ GenericToken) map[string]interface{} {
	if ro != nil {
		return map[string]interface{}{
			"user": ro.ID(),
		}
	}
	return nil
}
func DefaultPolicy(notary *heat.Notary) *Policy {
	return &Policy{
		Notary:  notary,
		Token:   &Token{},
		Clients: []Client{&Application{}},
		Grants: func(*Context, Client) (Grants, error) {
			return Grants{}, nil
		},
		RedirectURIValidator: DefaultRedirectURIValidator,
		ResourceOwners: func(_ *Context, _ Client) ([]ResourceOwner, error) {
			return []ResourceOwner{&User{}}, nil
		},
		GrantStrategy:             DefaultGrantStrategy,
		ApprovalURL:               StaticApprovalURL(""),
		ApproveStrategy:           DefaultApproveStrategy,
		TokenData:                 DefaultTokenData,
		AccessTokenLifespan:       time.Hour,
		RefreshTokenLifespan:      7 * 24 * time.Hour,
		AuthorizationCodeLifespan: time.Minute,
	}
}
func (p *Policy) Issue(token GenericToken, client Client, resourceOwner ResourceOwner) (string, error) {
	data := token.GetTokenData()
	var extra stick.Map
	if p.TokenData != nil {
		extra = p.TokenData(client, resourceOwner, token)
	}
	key := Key{
		Base: heat.Base{
			ID:     token.ID(),
			Expiry: data.ExpiresAt,
		},
		Extra: extra,
	}
	str, err := p.Notary.Issue(&key)
	if err != nil {
		return "", nil
	}
	return str, nil
}