pow-auth / assent

Multi-provider framework in Elixir
https://powauth.com
MIT License
391 stars 45 forks source link

Assent.Strategy.Apple callback verification fails when using Assent.JWTAdapter.JOSE #18

Closed stuartbain closed 4 years ago

stuartbain commented 4 years ago

When using the Assent.JWTAdapter.JOSE for Assent.Strategy.Apple, the following error occurs:

** (FunctionClauseError) no function clause matching in Assent.JWTAdapter.JOSE.jwk/2    

    The following arguments were given to Assent.JWTAdapter.JOSE.jwk/2:

        # 1
        "RS256"

        # 2
        nil

    Attempted function clauses (showing 3 out of 3):

        defp jwk(<<"HS"::binary(), _rest::binary()>>, secret)
        defp jwk(_alg, key) when is_binary(key)
        defp jwk(_alg, key) when is_map(key)

    (assent) lib/assent/jwt_adapter/jose.ex:24: Assent.JWTAdapter.JOSE.jwk/2
    (assent) lib/assent/jwt_adapter/jose.ex:46: Assent.JWTAdapter.JOSE.verify/3
    (assent) lib/assent/strategies/apple.ex:108: Assent.Strategy.Apple.get_user/2
    (assent) lib/assent/strategies/oauth2.ex:237: Assent.Strategy.OAuth2.fetch_user/3
    (assent) lib/assent/strategies/oauth2/base.ex:69: Assent.Strategy.OAuth2.Base.callback/3

The error is caused by a nil parameter being passed for the public key in the following line: https://github.com/pow-auth/assent/blob/50f49b4e6ab557d935bffffac53e77245cfcdf64/lib/assent/strategies/apple.ex#L107

I was able to work around the issue by providing the Apple Public Key from https://appleid.apple.com/auth/keys as a configuration parameter as follows:

  def get_user(config, token) do
    public_key = Config.get(config, :public_key, nil)
    with {:ok, jwt} <- Helpers.verify_jwt(token["id_token"], public_key, config) do
      {:ok, jwt.claims}
    end
  end

with the :public_key specified in my config as follows:

config :my_app, :pow_assent,
  providers: [
    apple: [
      strategy: Assent.Strategy.Apple,
      client_id: System.get_env("APPLE_CLIENT_ID"),
      team_id: System.get_env("APPLE_TEAM_ID"),
      private_key_id: System.get_env("APPLE_PRIVATE_KEY_ID"),
      private_key: System.get_env("APPLE_PRIVATE_KEY"),
      jwt_adapter: Assent.JWTAdapter.JOSE,
      public_key: %{
        "kty" => "RSA",
        "kid" => "AIDOPK1",
        "use" => "sig",
        "alg" => "RS256",
        "n" =>
          "lxrwmuYSAsTfn-lUu4goZSXBD9ackM9OJuwUVQHmbZo6GW4Fu_auUdN5zI7Y1dEDfgt7m7QXWbHuMD01HLnD4eRtY-RNwCWdjNfEaY_esUPY3OVMrNDI15Ns13xspWS3q-13kdGv9jHI28P87RvMpjz_JCpQ5IM44oSyRnYtVJO-320SB8E2Bw92pmrenbp67KRUzTEVfGU4-obP5RZ09OxvCr1io4KJvEOjDJuuoClF66AT72WymtoMdwzUmhINjR0XSqK6H0MdWsjw7ysyd_JhmqX5CAaT9Pgi0J8lU_pcl215oANqjy7Ob-VMhug9eGyxAWVfu_1u6QJKePlE-w",
        "e" => "AQAB"
      }
    ]
  ]

Hard coding the Apple public key is just a work around to get me up and running. I notice that the Ueberauth Apple strategy fetches the Apple public key during the verification phase and I guess the Assent Apple strategy should do the same?

danschultzer commented 4 years ago

Thanks! This was a bug in the JOSE adapter, and fixed in master. I'm reopening this issue as it would be best if the JWT is verified.

danschultzer commented 4 years ago

The Apple strategy does the full OAuth 2 flow so verification of the JWT isn't strictly required, but would be nice to have. I'll get back to this later. I've released v0.1.4 🚀