package utils import ( "context" "fmt" "net/http" "strings" "github.com/deepmap/oapi-codegen/pkg/middleware" "github.com/getkin/kin-openapi/openapi3filter" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" ) const ( prefix = "Bearer " ) func NewAuthenticator(jwtUtil *JWT) openapi3filter.AuthenticationFunc { return func(ctx context.Context, input *openapi3filter.AuthenticationInput) error { if jwtUtil == nil { return errors.New( fmt.Errorf("jwt util is nil: %w", errors.ErrInvalidArgs), errors.ErrInvalidArgs, ) } return authenticate(ctx, jwtUtil, input) } } func authenticate(ctx context.Context, jwtUtil *JWT, input *openapi3filter.AuthenticationInput) error { if input.SecuritySchemeName != "Bearer" { return fmt.Errorf("security scheme %s != 'Bearer'", input.SecuritySchemeName) } // Now, we need to get the JWS from the request, to match the request expectations // against request contents. jws, err := parseJWSFromRequest(input.RequestValidationInput.Request) if err != nil { return err } // if the JWS is valid, we have a JWT, which will contain a bunch of claims. token, validateErr := jwtUtil.Validate(jws) if validateErr != nil { return validateErr } // Set the property on the echo context so the handler is able to // access the claims data we generate in here. echoCtx := middleware.GetEchoContext(ctx) echoCtx.Set(models.AuthJWTDecodedUserIDKey, token) return nil } // extracts a JWS string from an Authorization: Bearer header. func parseJWSFromRequest(request *http.Request) (string, errors.Error) { header := request.Header.Get("Authorization") if header == "" || !strings.HasPrefix(header, prefix) { return "", errors.New( fmt.Errorf("failed to parse jws from request header: %s", header), errors.ErrNoAccess, ) } return strings.TrimPrefix(header, prefix), nil }