lib/ueberauth/strategy/cognito/jwt_verifier.ex

defmodule Ueberauth.Strategy.Cognito.JwtVerifier do
  @moduledoc """
  Utilities for working with JSON Web Tokens
  """

  alias Ueberauth.Strategy.Cognito.Utilities

  @doc "Verifies that a JWT is valid: the signature is correct,
  and the audience is the AWS `client_id`"
  def verify(jwt, jwks, config) do
    with {:ok, claims_json} <- verified_claims(jwks, jwt),
         {:ok, claims} <- Jason.decode(claims_json),
         true <- claims["aud"] == config.client_id,
         true <- claims["exp"] > System.system_time(:second),
         true <- claims["iss"] == Utilities.jwk_url_prefix(config),
         true <- claims["token_use"] in ["id", "access"] do
      {:ok, claims}
    else
      _ ->
        {:error, :invalid_jwt}
    end
  end

  defp verified_claims(jwks, jwt) do
    individual_jwks = Enum.map(jwks["keys"], &JOSE.JWK.from(&1))

    Enum.find_value(individual_jwks, fn jwk ->
      case JOSE.JWS.verify_strict(jwk, ["RS256"], jwt) do
        {true, claims_json, _} -> {:ok, claims_json}
        _ -> nil
      end
    end)
  end
end