github.com/blend/go-sdk@v1.20220411.3/web/jwt_manager.go (about)

     1  /*
     2  
     3  Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file.
     5  
     6  */
     7  
     8  package web
     9  
    10  import (
    11  	"context"
    12  	"time"
    13  
    14  	"github.com/golang-jwt/jwt"
    15  
    16  	"github.com/blend/go-sdk/ex"
    17  )
    18  
    19  const (
    20  	// ErrJWTNonstandardClaims can be returned by the jwt manager keyfunc.
    21  	ErrJWTNonstandardClaims = ex.Class("jwt; invalid claims object; should be standard claims")
    22  )
    23  
    24  // NewJWTManager returns a new jwt manager from a key.
    25  func NewJWTManager(key []byte) *JWTManager {
    26  	return &JWTManager{
    27  		KeyProvider: func(_ *Session) ([]byte, error) {
    28  			return key, nil
    29  		},
    30  	}
    31  }
    32  
    33  // JWTManager is a manager for JWTs.
    34  type JWTManager struct {
    35  	KeyProvider func(*Session) ([]byte, error)
    36  }
    37  
    38  // Apply applies the jwtm to the given auth manager.
    39  func (jwtm JWTManager) Apply(am *AuthManager) {
    40  	am.SerializeHandler = jwtm.SerializeHandler
    41  	am.FetchHandler = jwtm.FetchHandler
    42  }
    43  
    44  //
    45  // auth manager hooks
    46  //
    47  
    48  // SerializeHandler is a shim to the auth manager.
    49  func (jwtm JWTManager) SerializeHandler(_ context.Context, session *Session) (output string, err error) {
    50  	var key []byte
    51  	key, err = jwtm.KeyProvider(session)
    52  	if err != nil {
    53  		return
    54  	}
    55  
    56  	token := jwt.NewWithClaims(jwt.SigningMethodHS512, jwtm.Claims(session))
    57  	output, err = token.SignedString(key)
    58  	return
    59  }
    60  
    61  // FetchHandler is a shim to the auth manager.
    62  func (jwtm JWTManager) FetchHandler(_ context.Context, sessionValue string) (*Session, error) {
    63  	var claims jwt.StandardClaims
    64  	_, err := jwt.ParseWithClaims(sessionValue, &claims, jwtm.KeyFunc)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	// do we check if the token is valid ???
    70  	return jwtm.FromClaims(&claims), nil
    71  }
    72  
    73  //
    74  // utility functions
    75  //
    76  
    77  // Claims returns the sesion as a JWT standard claims object.
    78  func (jwtm JWTManager) Claims(session *Session) *jwt.StandardClaims {
    79  	return &jwt.StandardClaims{
    80  		Id:        session.SessionID,
    81  		Audience:  session.BaseURL,
    82  		Issuer:    "go-web",
    83  		Subject:   session.UserID,
    84  		IssuedAt:  session.CreatedUTC.Unix(),
    85  		ExpiresAt: session.ExpiresUTC.Unix(),
    86  	}
    87  }
    88  
    89  // FromClaims returns a session from a given claims set.
    90  func (jwtm JWTManager) FromClaims(claims *jwt.StandardClaims) *Session {
    91  	return &Session{
    92  		SessionID:  claims.Id,
    93  		BaseURL:    claims.Audience,
    94  		UserID:     claims.Subject,
    95  		CreatedUTC: time.Unix(claims.IssuedAt, 0).In(time.UTC),
    96  		ExpiresUTC: time.Unix(claims.ExpiresAt, 0).In(time.UTC),
    97  	}
    98  }
    99  
   100  // KeyFunc is a shim function to get the key for a given token.
   101  func (jwtm JWTManager) KeyFunc(token *jwt.Token) (interface{}, error) {
   102  	typed, ok := token.Claims.(*jwt.StandardClaims)
   103  	if !ok {
   104  		return nil, ErrJWTNonstandardClaims
   105  	}
   106  	return jwtm.KeyProvider(jwtm.FromClaims(typed))
   107  }