github.com/tickoalcantara12/micro/v3@v3.0.0-20221007104245-9d75b9bcbab9/util/auth/token/jwt/jwt.go (about)

     1  // Copyright 2020 Asim Aslam
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     https://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  //
    15  // Original source: github.com/micro/go-micro/v3/util/token/jwt/jwt.go
    16  
    17  package jwt
    18  
    19  import (
    20  	"encoding/base64"
    21  	"strings"
    22  	"time"
    23  
    24  	"github.com/golang-jwt/jwt"
    25  	"github.com/tickoalcantara12/micro/v3/service/auth"
    26  	"github.com/tickoalcantara12/micro/v3/util/auth/token"
    27  )
    28  
    29  // authClaims to be encoded in the JWT
    30  type authClaims struct {
    31  	Type     string            `json:"type"`
    32  	Scopes   []string          `json:"scopes"`
    33  	Metadata map[string]string `json:"metadata"`
    34  	Name     string            `json:"name"`
    35  
    36  	jwt.StandardClaims
    37  }
    38  
    39  // JWT implementation of token provider
    40  type JWT struct {
    41  	opts token.Options
    42  }
    43  
    44  // NewTokenProvider returns an initialized basic provider
    45  func NewTokenProvider(opts ...token.Option) token.Provider {
    46  	return &JWT{
    47  		opts: token.NewOptions(opts...),
    48  	}
    49  }
    50  
    51  // Generate a new JWT
    52  func (j *JWT) Generate(acc *auth.Account, opts ...token.GenerateOption) (*token.Token, error) {
    53  	var priv []byte
    54  	if strings.HasPrefix(j.opts.PrivateKey, "-----BEGIN RSA PRIVATE KEY-----") {
    55  		priv = []byte(j.opts.PrivateKey)
    56  	} else {
    57  		var err error
    58  		priv, err = base64.StdEncoding.DecodeString(j.opts.PrivateKey)
    59  		if err != nil {
    60  			return nil, err
    61  		}
    62  	}
    63  
    64  	// parse the private key
    65  	key, err := jwt.ParseRSAPrivateKeyFromPEM(priv)
    66  	if err != nil {
    67  		return nil, token.ErrEncodingToken
    68  	}
    69  
    70  	// parse the options
    71  	options := token.NewGenerateOptions(opts...)
    72  
    73  	// backwards compatibility
    74  	name := acc.Name
    75  	if name == "" {
    76  		name = acc.ID
    77  	}
    78  
    79  	// generate the JWT
    80  	expiry := time.Now().Add(options.Expiry)
    81  	t := jwt.NewWithClaims(jwt.SigningMethodRS256, authClaims{
    82  		Type: acc.Type, Scopes: acc.Scopes, Metadata: acc.Metadata, Name: name,
    83  		StandardClaims: jwt.StandardClaims{
    84  			Subject:   acc.ID,
    85  			Issuer:    acc.Issuer,
    86  			ExpiresAt: expiry.Unix(),
    87  		},
    88  	})
    89  	tok, err := t.SignedString(key)
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  
    94  	// return the token
    95  	return &token.Token{
    96  		Token:   tok,
    97  		Expiry:  expiry,
    98  		Created: time.Now(),
    99  	}, nil
   100  }
   101  
   102  // Inspect a JWT
   103  func (j *JWT) Inspect(t string) (*auth.Account, error) {
   104  	// simple validation should be of form xxx.yyy.zzz i.e. contain two dots
   105  	if len(strings.Split(t, ".")) != 3 {
   106  		return nil, token.ErrInvalidToken
   107  	}
   108  
   109  	var pub []byte
   110  	if strings.HasPrefix(j.opts.PublicKey, "-----BEGIN CERTIFICATE-----") {
   111  		pub = []byte(j.opts.PublicKey)
   112  	} else {
   113  		var err error
   114  		pub, err = base64.StdEncoding.DecodeString(j.opts.PublicKey)
   115  		if err != nil {
   116  			return nil, err
   117  		}
   118  	}
   119  
   120  	// parse the public key
   121  	res, err := jwt.ParseWithClaims(t, &authClaims{}, func(token *jwt.Token) (interface{}, error) {
   122  		return jwt.ParseRSAPublicKeyFromPEM(pub)
   123  	})
   124  	if err != nil {
   125  		return nil, token.ErrInvalidToken
   126  	}
   127  
   128  	// validate the token
   129  	if !res.Valid {
   130  		return nil, token.ErrInvalidToken
   131  	}
   132  	claims, ok := res.Claims.(*authClaims)
   133  	if !ok {
   134  		return nil, token.ErrInvalidToken
   135  	}
   136  
   137  	// backwards compatibility
   138  	name := claims.Name
   139  	if name == "" {
   140  		name = claims.Subject
   141  	}
   142  
   143  	// return the token
   144  	return &auth.Account{
   145  		ID:       claims.Subject,
   146  		Issuer:   claims.Issuer,
   147  		Type:     claims.Type,
   148  		Scopes:   claims.Scopes,
   149  		Metadata: claims.Metadata,
   150  		Name:     name,
   151  	}, nil
   152  }
   153  
   154  // String returns JWT
   155  func (j *JWT) String() string {
   156  	return "jwt"
   157  }