github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/model/session/delegated.go (about)

     1  package session
     2  
     3  import (
     4  	"encoding/base64"
     5  	"errors"
     6  	"time"
     7  
     8  	jwt "github.com/golang-jwt/jwt/v5"
     9  
    10  	"github.com/cozy/cozy-stack/model/instance"
    11  	"github.com/cozy/cozy-stack/pkg/config/config"
    12  	"github.com/cozy/cozy-stack/pkg/crypto"
    13  )
    14  
    15  // ExternalClaims is the format for JWT for authentication from external sources
    16  type ExternalClaims struct {
    17  	jwt.RegisteredClaims
    18  	Name  string `json:"name"`
    19  	Code  string `json:"code"`
    20  	Email string `json:"email,omitempty"`
    21  	UUID  string `json:"uuid,omitempty"`
    22  }
    23  
    24  // CheckDelegatedJWT checks if a delegated JWT is valid for a given instance
    25  func CheckDelegatedJWT(instance *instance.Instance, token string) error {
    26  	authenticationConfig := config.GetConfig().Authentication
    27  	context := instance.ContextName
    28  
    29  	if context == "" {
    30  		context = config.DefaultInstanceContext
    31  	}
    32  	delegatedTypes, ok := authenticationConfig[context]
    33  	if !ok {
    34  		return errors.New("No delegated authentication defined for this context")
    35  	}
    36  
    37  	JWTSecret, ok := delegatedTypes.(map[string]interface{})["jwt_secret"]
    38  	if !ok {
    39  		return errors.New("JWT delegated type is not defined for this context")
    40  	}
    41  
    42  	claims := ExternalClaims{}
    43  	keyFunc := func(token *jwt.Token) (interface{}, error) {
    44  		return base64.StdEncoding.DecodeString(JWTSecret.(string))
    45  	}
    46  
    47  	err := crypto.ParseJWT(token, keyFunc, &claims)
    48  	if err != nil {
    49  		return err
    50  	}
    51  
    52  	if claims.RegisteredClaims.ExpiresAt != nil && claims.RegisteredClaims.ExpiresAt.Before(time.Now()) {
    53  		return errors.New("Token has expired")
    54  	}
    55  
    56  	if claims.Name != instance.Domain {
    57  		return errors.New("Issuer is not valid")
    58  	}
    59  
    60  	return nil
    61  }