Sha256: c4f39b6ab3ded5351fa935e786b86234b758b17dd9929e60c72ea813de86c63b

Contents?: true

Size: 1.42 KB

Versions: 2

Compression:

Stored size: 1.42 KB

Contents

# frozen_string_literal: true

module KeycloakRack
  # Accept an encoded JWT and return the raw token.
  class DecodeAndVerify
    include Dry::Monads[:do, :result]

    include Import[
      config: "keycloak-rack.config",
      key_resolver: "keycloak-rack.key_resolver",
    ]

    delegate :token_leeway, to: :config

    # @param [String] token
    # @return [Dry::Monads::Success(Hash, Hash)] a tuple of the JWT payload and its headers
    # @return [Dry::Monads::Failure(:expired, String, String, Exception)]
    # @return [Dry::Monads::Failure(:decoding_failed, String, Exception)]
    def call(token)
      jwks = yield key_resolver.find_public_keys

      algorithms = yield algorithms_for jwks

      options = {
        algorithms: algorithms,
        leeway: token_leeway,
        jwks: jwks
      }

      payload, headers = JWT.decode token, nil, true, options
    rescue JWT::ExpiredSignature => e
      Failure[:expired, "JWT is expired", token, e]
    rescue JWT::DecodeError => e
      Failure[:decoding_failed, "Failed to decode JWT", e]
    else
      Success[payload, headers]
    end

    private

    # @param [{ Symbol => <{ Symbol => String }> }] jwks
    # @return [<String>]
    def algorithms_for(jwks)
      jwks.fetch(:keys, []).map do |k|
        k[:alg]
      end.uniq.compact.then do |algs|
        algs.present? ? Success(algs) : Failure[:no_algorithms, "Could not derive algorithms from JWKS"]
      end
    end
  end
end

Version data entries

2 entries across 2 versions & 1 rubygems

Version Path
keycloak_rack-1.1.1 lib/keycloak_rack/decode_and_verify.rb
keycloak_rack-1.1.0 lib/keycloak_rack/decode_and_verify.rb