go-micro.dev/v5@v5.12.0/auth/jwt/jwt.go (about)

     1  package jwt
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	jwtToken "github.com/micro/plugins/v5/auth/jwt/token"
     8  	"go-micro.dev/v5/auth"
     9  	"go-micro.dev/v5/cmd"
    10  )
    11  
    12  func init() {
    13  	cmd.DefaultAuths["jwt"] = NewAuth
    14  }
    15  
    16  // NewAuth returns a new instance of the Auth service.
    17  func NewAuth(opts ...auth.Option) auth.Auth {
    18  	j := new(jwt)
    19  	j.Init(opts...)
    20  	return j
    21  }
    22  
    23  func NewRules() auth.Rules {
    24  	return new(jwtRules)
    25  }
    26  
    27  type jwt struct {
    28  	sync.Mutex
    29  	options auth.Options
    30  	jwt     jwtToken.Provider
    31  }
    32  
    33  type jwtRules struct {
    34  	sync.Mutex
    35  	rules []*auth.Rule
    36  }
    37  
    38  func (j *jwt) String() string {
    39  	return "jwt"
    40  }
    41  
    42  func (j *jwt) Init(opts ...auth.Option) {
    43  	j.Lock()
    44  	defer j.Unlock()
    45  
    46  	for _, o := range opts {
    47  		o(&j.options)
    48  	}
    49  
    50  	j.jwt = jwtToken.New(
    51  		jwtToken.WithPrivateKey(j.options.PrivateKey),
    52  		jwtToken.WithPublicKey(j.options.PublicKey),
    53  	)
    54  }
    55  
    56  func (j *jwt) Options() auth.Options {
    57  	j.Lock()
    58  	defer j.Unlock()
    59  	return j.options
    60  }
    61  
    62  func (j *jwt) Generate(id string, opts ...auth.GenerateOption) (*auth.Account, error) {
    63  	options := auth.NewGenerateOptions(opts...)
    64  	account := &auth.Account{
    65  		ID:       id,
    66  		Type:     options.Type,
    67  		Scopes:   options.Scopes,
    68  		Metadata: options.Metadata,
    69  		Issuer:   j.Options().Namespace,
    70  	}
    71  
    72  	// generate a JWT secret which can be provided to the Token() method
    73  	// and exchanged for an access token
    74  	secret, err := j.jwt.Generate(account)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  	account.Secret = secret.Token
    79  
    80  	// return the account
    81  	return account, nil
    82  }
    83  
    84  func (j *jwtRules) Grant(rule *auth.Rule) error {
    85  	j.Lock()
    86  	defer j.Unlock()
    87  	j.rules = append(j.rules, rule)
    88  	return nil
    89  }
    90  
    91  func (j *jwtRules) Revoke(rule *auth.Rule) error {
    92  	j.Lock()
    93  	defer j.Unlock()
    94  
    95  	rules := make([]*auth.Rule, 0, len(j.rules))
    96  	for _, r := range j.rules {
    97  		if r.ID != rule.ID {
    98  			rules = append(rules, r)
    99  		}
   100  	}
   101  
   102  	j.rules = rules
   103  	return nil
   104  }
   105  
   106  func (j *jwtRules) Verify(acc *auth.Account, res *auth.Resource, opts ...auth.VerifyOption) error {
   107  	j.Lock()
   108  	defer j.Unlock()
   109  
   110  	var options auth.VerifyOptions
   111  	for _, o := range opts {
   112  		o(&options)
   113  	}
   114  
   115  	return auth.Verify(j.rules, acc, res)
   116  }
   117  
   118  func (j *jwtRules) List(opts ...auth.ListOption) ([]*auth.Rule, error) {
   119  	j.Lock()
   120  	defer j.Unlock()
   121  	return j.rules, nil
   122  }
   123  
   124  func (j *jwt) Inspect(token string) (*auth.Account, error) {
   125  	return j.jwt.Inspect(token)
   126  }
   127  
   128  func (j *jwt) Token(opts ...auth.TokenOption) (*auth.Token, error) {
   129  	options := auth.NewTokenOptions(opts...)
   130  
   131  	secret := options.RefreshToken
   132  	if len(options.Secret) > 0 {
   133  		secret = options.Secret
   134  	}
   135  
   136  	account, err := j.jwt.Inspect(secret)
   137  	if err != nil {
   138  		return nil, err
   139  	}
   140  
   141  	access, err := j.jwt.Generate(account, jwtToken.WithExpiry(options.Expiry))
   142  	if err != nil {
   143  		return nil, err
   144  	}
   145  
   146  	refresh, err := j.jwt.Generate(account, jwtToken.WithExpiry(options.Expiry+time.Hour))
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  
   151  	return &auth.Token{
   152  		Created:      access.Created,
   153  		Expiry:       access.Expiry,
   154  		AccessToken:  access.Token,
   155  		RefreshToken: refresh.Token,
   156  	}, nil
   157  }