diff --git a/lib/realtime_web/channels/auth/channels_authorization.ex b/lib/realtime_web/channels/auth/channels_authorization.ex index 44291ade2..109dbe660 100644 --- a/lib/realtime_web/channels/auth/channels_authorization.ex +++ b/lib/realtime_web/channels/auth/channels_authorization.ex @@ -5,17 +5,17 @@ defmodule RealtimeWeb.ChannelsAuthorization do require Logger import Realtime.Logs + @doc """ + Authorize connection to access channel + """ + @spec authorize(binary(), binary(), binary() | nil) :: {:ok, map()} | {:error, any()} def authorize(token, jwt_secret, jwt_jwks) when is_binary(token) do token |> clean_token() |> RealtimeWeb.JwtVerification.verify(jwt_secret, jwt_jwks) end - def authorize(_token, _jwt_secret, _jwt_jwks), do: :error - - defp clean_token(token) do - Regex.replace(~r/\s|\n/, URI.decode(token), "") - end + def authorize(_token, _jwt_secret, _jwt_jwks), do: {:error, :invalid_token} def authorize_conn(token, jwt_secret, jwt_jwks) do case authorize(token, jwt_secret, jwt_jwks) do @@ -30,11 +30,10 @@ defmodule RealtimeWeb.ChannelsAuthorization do end {:error, reason} -> + log_error("ErrorAuthorizingWebsocket", reason) {:error, reason} - - error -> - log_error("ErrorAuthorizingWebsocket", error) - {:error, :unknown} end end + + defp clean_token(token), do: Regex.replace(~r/\s|\n/, URI.decode(token), "") end diff --git a/lib/realtime_web/channels/auth/jwt_verification.ex b/lib/realtime_web/channels/auth/jwt_verification.ex index c876c667d..293d4e5f4 100644 --- a/lib/realtime_web/channels/auth/jwt_verification.ex +++ b/lib/realtime_web/channels/auth/jwt_verification.ex @@ -29,6 +29,10 @@ defmodule RealtimeWeb.JwtVerification do @es_algorithms ["ES256", "ES384", "ES512"] @ed_algorithms ["Ed25519", "Ed448"] + @doc """ + Verify JWT token and validate claims + """ + @spec verify(binary(), binary(), binary() | nil) :: {:ok, map()} | {:error, any()} def verify(token, jwt_secret, jwt_jwks) when is_binary(token) do with {:ok, _claims} <- check_claims_format(token), {:ok, header} <- check_header_format(token), diff --git a/mix.exs b/mix.exs index 385df1ba7..aae74c1e8 100644 --- a/mix.exs +++ b/mix.exs @@ -4,7 +4,7 @@ defmodule Realtime.MixProject do def project do [ app: :realtime, - version: "2.33.82", + version: "2.33.83", elixir: "~> 1.17.3", elixirc_paths: elixirc_paths(Mix.env()), start_permanent: Mix.env() == :prod, diff --git a/test/realtime_web/channels/auth/channels_authorization_test.exs b/test/realtime_web/channels/auth/channels_authorization_test.exs index a8d6fc80a..3e27c6b11 100644 --- a/test/realtime_web/channels/auth/channels_authorization_test.exs +++ b/test/realtime_web/channels/auth/channels_authorization_test.exs @@ -1,40 +1,40 @@ defmodule RealtimeWeb.ChannelsAuthorizationTest do use ExUnit.Case - import Mock import Generators alias RealtimeWeb.{ChannelsAuthorization, JwtVerification} @secret "" - - test "authorize/3 when token is authorized" do - input_token = "\n token %20 1 %20 2 %20 3 " - expected_token = "token123" - - with_mock JwtVerification, - verify: fn token, @secret, _jwks -> - assert token == expected_token - {:ok, %{}} - end do - assert {:ok, %{}} = ChannelsAuthorization.authorize(input_token, @secret, nil) + describe "authorize_conn/3" do + test "when token is authorized" do + input_token = "\n token %20 1 %20 2 %20 3 " + expected_token = "token123" + + with_mock JwtVerification, + verify: fn token, @secret, _jwks -> + assert token == expected_token + {:ok, %{}} + end do + assert {:ok, %{}} = ChannelsAuthorization.authorize(input_token, @secret, nil) + end end - end - test "authorize/3 when token is unauthorized" do - with_mock JwtVerification, verify: fn _token, _secret, _jwks -> :error end do - assert :error = ChannelsAuthorization.authorize("bad_token", @secret, nil) + test "when token is unauthorized" do + with_mock JwtVerification, verify: fn _token, _secret, _jwks -> :error end do + assert :error = ChannelsAuthorization.authorize("bad_token", @secret, nil) + end end - end - test "authorize/3 when token is not a string" do - assert :error = ChannelsAuthorization.authorize([], @secret, nil) - end + test "when token is not a string" do + assert {:error, :invalid_token} = ChannelsAuthorization.authorize([], @secret, nil) + end - test "authorize_conn/3 fails when has missing headers" do - jwt = generate_jwt_token(@secret, %{}) + test "authorize_conn/3 fails when has missing headers" do + jwt = generate_jwt_token(@secret, %{}) - assert {:error, :missing_claims} = - ChannelsAuthorization.authorize_conn(jwt, @secret, nil) + assert {:error, :missing_claims} = + ChannelsAuthorization.authorize_conn(jwt, @secret, nil) + end end end diff --git a/test/realtime_web/channels/auth/jwt_verification_test.exs b/test/realtime_web/channels/auth/jwt_verification_test.exs index ca70ef02c..44d183e80 100644 --- a/test/realtime_web/channels/auth/jwt_verification_test.exs +++ b/test/realtime_web/channels/auth/jwt_verification_test.exs @@ -17,217 +17,252 @@ defmodule RealtimeWeb.JwtVerificationTest do :ok end - test "verify/3 when token is not a string" do - assert {:error, :not_a_string} = JwtVerification.verify([], @jwt_secret, nil) - end - - test "verify/3 when token has invalid format" do - invalid_token = Base.encode64("{}") - - assert {:error, :expected_claims_map} = - JwtVerification.verify(invalid_token, @jwt_secret, nil) - end - - test "verify/3 when token header is not a map" do - invalid_token = - Base.encode64("[]") <> "." <> Base.encode64("{}") <> "." <> Base.encode64("<<\"sig\">>") - - assert {:error, _reason} = JwtVerification.verify(invalid_token, @jwt_secret, nil) - end - - test "verify/3 when token claims is not a map" do - invalid_token = - Base.encode64("{}") <> "." <> Base.encode64("[]") <> "." <> Base.encode64("<<\"sig\">>") - - assert {:error, _reason} = JwtVerification.verify(invalid_token, @jwt_secret, nil) - end - - test "verify/3 when token header does not have typ or alg" do - invalid_token = - Base.encode64("{\"typ\": \"JWT\"}") <> - "." <> Base.encode64("{}") <> "." <> Base.encode64("<<\"sig\">>") - - assert {:error, _reason} = JwtVerification.verify(invalid_token, @jwt_secret, nil) - - invalid_token = - Base.encode64("{\"alg\": \"HS256\"}") <> - "." <> Base.encode64("{}") <> "." <> Base.encode64("<<\"sig\">>") + describe "verify/3" do + test "when token is not a string" do + assert {:error, :not_a_string} = JwtVerification.verify([], @jwt_secret, nil) + end - assert {:error, _reason} = JwtVerification.verify(invalid_token, @jwt_secret, nil) - end + test "when token has invalid format" do + invalid_token = Base.encode64("{}") - test "verify/3 when token header alg is not allowed" do - invalid_token = - Base.encode64("{\"typ\": \"JWT\", \"alg\": \"ZZ999\"}") <> - "." <> Base.encode64("{}") <> "." <> Base.encode64("<<\"sig\">>") + assert {:error, :expected_claims_map} = + JwtVerification.verify(invalid_token, @jwt_secret, nil) + end - assert {:error, _reason} = JwtVerification.verify(invalid_token, @jwt_secret, nil) - end + test "when token header is not a map" do + invalid_token = + Base.encode64("[]") <> "." <> Base.encode64("{}") <> "." <> Base.encode64("<<\"sig\">>") - test "verify/3 when token is valid and alg is HS256" do - signer = Joken.Signer.create("HS256", @jwt_secret) + assert {:error, _reason} = JwtVerification.verify(invalid_token, @jwt_secret, nil) + end - token = Joken.generate_and_sign!(%{}, %{}, signer) + test "when token claims is not a map" do + invalid_token = + Base.encode64("{}") <> "." <> Base.encode64("[]") <> "." <> Base.encode64("<<\"sig\">>") - assert {:ok, _claims} = JwtVerification.verify(token, @jwt_secret, nil) - end + assert {:error, _reason} = JwtVerification.verify(invalid_token, @jwt_secret, nil) + end - test "verify/3 when token is valid and alg is HS384" do - signer = Joken.Signer.create("HS384", @jwt_secret) + test "when token header does not have typ or alg" do + invalid_token = + Base.encode64("{\"typ\": \"JWT\"}") <> + "." <> Base.encode64("{}") <> "." <> Base.encode64("<<\"sig\">>") - token = Joken.generate_and_sign!(%{}, %{}, signer) + assert {:error, _reason} = JwtVerification.verify(invalid_token, @jwt_secret, nil) - assert {:ok, _claims} = JwtVerification.verify(token, @jwt_secret, nil) - end + invalid_token = + Base.encode64("{\"alg\": \"HS256\"}") <> + "." <> Base.encode64("{}") <> "." <> Base.encode64("<<\"sig\">>") - test "verify/3 when token is valid and alg is HS512" do - signer = Joken.Signer.create("HS512", @jwt_secret) + assert {:error, _reason} = JwtVerification.verify(invalid_token, @jwt_secret, nil) + end - token = Joken.generate_and_sign!(%{}, %{}, signer) + test "when token header alg is not allowed" do + invalid_token = + Base.encode64("{\"typ\": \"JWT\", \"alg\": \"ZZ999\"}") <> + "." <> Base.encode64("{}") <> "." <> Base.encode64("<<\"sig\">>") - assert {:ok, _claims} = JwtVerification.verify(token, @jwt_secret, nil) - end + assert {:error, _reason} = JwtVerification.verify(invalid_token, @jwt_secret, nil) + end - test "verify/3 when token has expired" do - signer = Joken.Signer.create(@alg, @jwt_secret) - - current_time = 1_610_086_801 - Mock.freeze(current_time) - - token = - Joken.generate_and_sign!( - %{ - "exp" => %Joken.Claim{generate: fn -> current_time end} - }, - %{}, - signer - ) - - assert {:error, [message: "Invalid token", claim: "exp", claim_val: 1_610_086_801]} = - JwtVerification.verify(token, @jwt_secret, nil) - - token = - Joken.generate_and_sign!( - %{ - "exp" => %Joken.Claim{generate: fn -> current_time - 1 end} - }, - %{}, - signer - ) - - assert {:error, [message: "Invalid token", claim: "exp", claim_val: 1_610_086_800]} = - JwtVerification.verify(token, @jwt_secret, nil) - end + test "when token is valid and alg is HS256" do + signer = Joken.Signer.create("HS256", @jwt_secret) - test "verify/3 when token has not expired" do - signer = Joken.Signer.create(@alg, @jwt_secret) + token = Joken.generate_and_sign!(%{}, %{}, signer) - Mock.freeze() - current_time = Mock.current_time() + assert {:ok, _claims} = JwtVerification.verify(token, @jwt_secret, nil) + end - token = - Joken.generate_and_sign!( - %{ - "exp" => %Joken.Claim{generate: fn -> current_time + 1 end} - }, - %{}, - signer - ) + test "when token is valid and alg is HS384" do + signer = Joken.Signer.create("HS384", @jwt_secret) - assert {:ok, _claims} = JwtVerification.verify(token, @jwt_secret, nil) - end - - test "verify/3 when token claims match expected claims from :jwt_claim_validators config" do - Application.put_env(:realtime, :jwt_claim_validators, %{ - "iss" => "Tester", - "aud" => "www.test.com" - }) - - signer = Joken.Signer.create(@alg, @jwt_secret) - - Mock.freeze() - current_time = Mock.current_time() - - token = - Joken.generate_and_sign!( - %{ - "exp" => %Joken.Claim{generate: fn -> current_time + 1 end}, - "iss" => %Joken.Claim{generate: fn -> "Tester" end}, - "aud" => %Joken.Claim{generate: fn -> "www.test.com" end}, - "sub" => %Joken.Claim{generate: fn -> "tester@test.com" end} - }, - %{}, - signer - ) - - assert {:ok, _claims} = JwtVerification.verify(token, @jwt_secret, nil) - end - - test "verify/3 when token claims do not match expected claims from :jwt_claim_validators config" do - Application.put_env(:realtime, :jwt_claim_validators, %{ - "iss" => "Issuer", - "aud" => "www.test.com" - }) - - signer = Joken.Signer.create(@alg, @jwt_secret) - - Mock.freeze() - current_time = Mock.current_time() - - token = - Joken.generate_and_sign!( - %{ - "exp" => %Joken.Claim{generate: fn -> current_time + 1 end}, - "iss" => %Joken.Claim{generate: fn -> "Tester" end}, - "aud" => %Joken.Claim{generate: fn -> "www.test.com" end}, - "sub" => %Joken.Claim{generate: fn -> "tester@test.com" end} - }, - %{}, - signer - ) - - assert {:error, [message: "Invalid token", claim: "iss", claim_val: "Tester"]} = - JwtVerification.verify(token, @jwt_secret, nil) - end - - test "verify/3 using RS256 JWK" do - jwks = %{ - "keys" => [ - %{ - "kty" => "RSA", - "n" => - "6r1mKwCalvJ0NyThyQkBr5huFILwwhXcxtsdlw-WybNz4avzODQwLFkA-b2fnnfdFgualV2NdcvoJSo1bzVGCWWqwWKWdTQKFjtcjAIC4FnhOv5ynNF9Ub-11ORDd1aiq_4XKNA4GaS1HqBekVDAAvJYy99Jz0CkLx4NU_VrS0U9sOQzUAhy2MwZCx2kZ3SWKEMjjEIkbvIb22IdRTyuFsAndKGpyzhw-MalnU5P2hOig-QApNBc0WJtTHTAa4PLQ6v_5jNc5PzCwP8jGK9SlrSF-GOnx9BVBX9t-AIDp-BviKbtY7y-pku6-f7HSiS2T3iAJkHXPm9E_NwwhWzMJQ", - "e" => "AQAB", - "kid" => "key-id-1" - } - ] - } - - token = - "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtleS1pZC0xIn0.eyJpYXQiOjE3MTIwNDc1NjUsInJvbGUiOiJhdXRoZW50aWNhdGVkIiwic3ViIjoidXNlci1pZCIsImV4cCI6MTcxMjA1MTE2NX0.zUeoZrWK1efAc4q9y978_9qkhdXktdjf5H8O9Rw0SHcPaXW8OBcuNR2huRrgORvqFx6_sHn6nCJaWkZGzO-f8wskMD7Z4INq2JUypr6nASie3Qu2lLyeY3WTInaXNAKH-oqlfTLRskbz8zkIxOj2bBJiN9ceQLkJU-c92ndiuiG5D1jyQrGsvRdFem_cemp0yOoEaC0XWdjeV6C_UD-34GIyv3o8H4HZg1GcCiyNnAfDmLAcTOQPmqkwsRDQb-pm5O3HwpQt9WHOB6i1vzf-nmIGyCRA7STPdALK16-aiAyT4SJRxM5WN3iK8yitH7g4JETb9WocBbwIM_zfNnUI5w" - - # Check that the signature is valid even though time may be off. - assert {:error, :signature_error} != JwtVerification.verify(token, @jwt_secret, jwks) - end + token = Joken.generate_and_sign!(%{}, %{}, signer) - test "verify/3 using ES256 JWK" do - jwks = %{ - "keys" => [ - %{ - "kty" => "EC", - "x" => "iX_niXPSL2nW-9IyCELzyceAtuE3B98pWML5tQGACD4", - "y" => "kT02DoLhXx6gtpkbrN8XwQ2wtzE6cDBaqlWgVXIeqV0", - "crv" => "P-256", - "d" => "FBVYnsYA2C3FTggEwV8kCRMo4FLl220_cWY2RdXyb_8", - "kid" => "key-id-1" - } - ] - } - - token = - "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6ImtleS1pZC0xIn0.eyJpYXQiOjE3MTIwNDk2NTcsInJvbGUiOiJhdXRoZW50aWNhdGVkIiwic3ViIjoidXNlci1pZCIsImV4cCI6MTcxMjA1MzI1N30.IIQBuEiSnZacGMqiqsrLAeRGOjIaB4F3x1gnLN5zvhFryJ-6tdgu96lFv5HUF13IL2UfHWad0OuvoDt4DEHRxw" - - # Check that the signature is valid even though time may be off. - assert {:error, :signature_error} != JwtVerification.verify(token, @jwt_secret, jwks) + assert {:ok, _claims} = JwtVerification.verify(token, @jwt_secret, nil) + end + + test "when token is valid and alg is HS512" do + signer = Joken.Signer.create("HS512", @jwt_secret) + + token = Joken.generate_and_sign!(%{}, %{}, signer) + + assert {:ok, _claims} = JwtVerification.verify(token, @jwt_secret, nil) + end + + test "when token has expired" do + signer = Joken.Signer.create(@alg, @jwt_secret) + + current_time = 1_610_086_801 + Mock.freeze(current_time) + + token = + Joken.generate_and_sign!( + %{ + "exp" => %Joken.Claim{generate: fn -> current_time end} + }, + %{}, + signer + ) + + assert {:error, [message: "Invalid token", claim: "exp", claim_val: 1_610_086_801]} = + JwtVerification.verify(token, @jwt_secret, nil) + + token = + Joken.generate_and_sign!( + %{ + "exp" => %Joken.Claim{generate: fn -> current_time - 1 end} + }, + %{}, + signer + ) + + assert {:error, [message: "Invalid token", claim: "exp", claim_val: 1_610_086_800]} = + JwtVerification.verify(token, @jwt_secret, nil) + end + + test "when token has not expired" do + signer = Joken.Signer.create(@alg, @jwt_secret) + + Mock.freeze() + current_time = Mock.current_time() + + token = + Joken.generate_and_sign!( + %{ + "exp" => %Joken.Claim{generate: fn -> current_time + 1 end} + }, + %{}, + signer + ) + + assert {:ok, _claims} = JwtVerification.verify(token, @jwt_secret, nil) + end + + test "when token claims match expected claims from :jwt_claim_validators config" do + Application.put_env(:realtime, :jwt_claim_validators, %{ + "iss" => "Tester", + "aud" => "www.test.com" + }) + + signer = Joken.Signer.create(@alg, @jwt_secret) + + Mock.freeze() + current_time = Mock.current_time() + + token = + Joken.generate_and_sign!( + %{ + "exp" => %Joken.Claim{generate: fn -> current_time + 1 end}, + "iss" => %Joken.Claim{generate: fn -> "Tester" end}, + "aud" => %Joken.Claim{generate: fn -> "www.test.com" end}, + "sub" => %Joken.Claim{generate: fn -> "tester@test.com" end} + }, + %{}, + signer + ) + + assert {:ok, _claims} = JwtVerification.verify(token, @jwt_secret, nil) + end + + test "when token claims do not match expected claims from :jwt_claim_validators config" do + Application.put_env(:realtime, :jwt_claim_validators, %{ + "iss" => "Issuer", + "aud" => "www.test.com" + }) + + signer = Joken.Signer.create(@alg, @jwt_secret) + + Mock.freeze() + current_time = Mock.current_time() + + token = + Joken.generate_and_sign!( + %{ + "exp" => %Joken.Claim{generate: fn -> current_time + 1 end}, + "iss" => %Joken.Claim{generate: fn -> "Tester" end}, + "aud" => %Joken.Claim{generate: fn -> "www.test.com" end}, + "sub" => %Joken.Claim{generate: fn -> "tester@test.com" end} + }, + %{}, + signer + ) + + assert {:error, [message: "Invalid token", claim: "iss", claim_val: "Tester"]} = + JwtVerification.verify(token, @jwt_secret, nil) + end + + test "using RS256 JWK" do + jwks = %{ + "keys" => [ + %{ + "kty" => "RSA", + "n" => + "6r1mKwCalvJ0NyThyQkBr5huFILwwhXcxtsdlw-WybNz4avzODQwLFkA-b2fnnfdFgualV2NdcvoJSo1bzVGCWWqwWKWdTQKFjtcjAIC4FnhOv5ynNF9Ub-11ORDd1aiq_4XKNA4GaS1HqBekVDAAvJYy99Jz0CkLx4NU_VrS0U9sOQzUAhy2MwZCx2kZ3SWKEMjjEIkbvIb22IdRTyuFsAndKGpyzhw-MalnU5P2hOig-QApNBc0WJtTHTAa4PLQ6v_5jNc5PzCwP8jGK9SlrSF-GOnx9BVBX9t-AIDp-BviKbtY7y-pku6-f7HSiS2T3iAJkHXPm9E_NwwhWzMJQ", + "e" => "AQAB", + "kid" => "key-id-1" + } + ] + } + + token = + "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtleS1pZC0xIn0.eyJpYXQiOjE3MTIwNDc1NjUsInJvbGUiOiJhdXRoZW50aWNhdGVkIiwic3ViIjoidXNlci1pZCIsImV4cCI6MTcxMjA1MTE2NX0.zUeoZrWK1efAc4q9y978_9qkhdXktdjf5H8O9Rw0SHcPaXW8OBcuNR2huRrgORvqFx6_sHn6nCJaWkZGzO-f8wskMD7Z4INq2JUypr6nASie3Qu2lLyeY3WTInaXNAKH-oqlfTLRskbz8zkIxOj2bBJiN9ceQLkJU-c92ndiuiG5D1jyQrGsvRdFem_cemp0yOoEaC0XWdjeV6C_UD-34GIyv3o8H4HZg1GcCiyNnAfDmLAcTOQPmqkwsRDQb-pm5O3HwpQt9WHOB6i1vzf-nmIGyCRA7STPdALK16-aiAyT4SJRxM5WN3iK8yitH7g4JETb9WocBbwIM_zfNnUI5w" + + # Check that the signature is valid even though time may be off. + assert {:error, :signature_error} != JwtVerification.verify(token, @jwt_secret, jwks) + end + + test "using ES256 JWK" do + jwks = %{ + "keys" => [ + %{ + "kty" => "EC", + "x" => "iX_niXPSL2nW-9IyCELzyceAtuE3B98pWML5tQGACD4", + "y" => "kT02DoLhXx6gtpkbrN8XwQ2wtzE6cDBaqlWgVXIeqV0", + "crv" => "P-256", + "d" => "FBVYnsYA2C3FTggEwV8kCRMo4FLl220_cWY2RdXyb_8", + "kid" => "key-id-1" + } + ] + } + + token = + "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiIsImtpZCI6ImtleS1pZC0xIn0.eyJpYXQiOjE3MTIwNDk2NTcsInJvbGUiOiJhdXRoZW50aWNhdGVkIiwic3ViIjoidXNlci1pZCIsImV4cCI6MTcxMjA1MzI1N30.IIQBuEiSnZacGMqiqsrLAeRGOjIaB4F3x1gnLN5zvhFryJ-6tdgu96lFv5HUF13IL2UfHWad0OuvoDt4DEHRxw" + + # Check that the signature is valid even though time may be off. + assert {:error, :signature_error} != JwtVerification.verify(token, @jwt_secret, jwks) + end + + test "returns error when no matching JWK is found for RSA algorithm" do + # Replace with a valid JWT structure + token = + "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtleS1pZC0xIn0.eyJpYXQiOjE3MTIwNDc1NjUsInJvbGUiOiJhdXRoZW50aWNhdGVkIiwic3ViIjoidXNlci1pZCIsImV4cCI6MTcxMjA1MTE2NX0.zUeoZrWK1efAc4q9y978_9qkhdXktdjf5H8O9Rw0SHcPaXW8OBcuNR2huRrgORvqFx6_sHn6nCJaWkZGzO-f8wskMD7Z4INq2JUypr6nASie3Qu2lLyeY3WTInaXNAKH-oqlfTLRskbz8zkIxOj2bBJiN9ceQLkJU-c92ndiuiG5D1jyQrGsvRdFem_cemp0yOoEaC0XWdjeV6C_UD-34GIyv3o8H4HZg1GcCiyNnAfDmLAcTOQPmqkwsRDQb-pm5O3HwpQt9WHOB6i1vzf-nmIGyCRA7STPdALK16-aiAyT4SJRxM5WN3iK8yitH7g4JETb9WocBbwIM_zfNnUI5w" + + jwt_secret = "secret" + jwks = %{"keys" => [%{"kty" => "RSA", "kid" => "some_other_kid"}]} + + assert {:error, :error_generating_signer} = JwtVerification.verify(token, jwt_secret, jwks) + end + + test "returns error when no matching JWK is found for EC algorithm" do + # Replace with a valid JWT structure + token = + "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtleS1pZC0xIn0.eyJpYXQiOjE3MTIwNDc1NjUsInJvbGUiOiJhdXRoZW50aWNhdGVkIiwic3ViIjoidXNlci1pZCIsImV4cCI6MTcxMjA1MTE2NX0.zUeoZrWK1efAc4q9y978_9qkhdXktdjf5H8O9Rw0SHcPaXW8OBcuNR2huRrgORvqFx6_sHn6nCJaWkZGzO-f8wskMD7Z4INq2JUypr6nASie3Qu2lLyeY3WTInaXNAKH-oqlfTLRskbz8zkIxOj2bBJiN9ceQLkJU-c92ndiuiG5D1jyQrGsvRdFem_cemp0yOoEaC0XWdjeV6C_UD-34GIyv3o8H4HZg1GcCiyNnAfDmLAcTOQPmqkwsRDQb-pm5O3HwpQt9WHOB6i1vzf-nmIGyCRA7STPdALK16-aiAyT4SJRxM5WN3iK8yitH7g4JETb9WocBbwIM_zfNnUI5w" + + jwt_secret = "secret" + jwks = %{"keys" => [%{"kty" => "EC", "kid" => "some_other_kid"}]} + + assert {:error, :error_generating_signer} = JwtVerification.verify(token, jwt_secret, jwks) + end + + test "returns error when no matching JWK is found for OKP algorithm" do + # Replace with a valid JWT structure + token = + "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImtleS1pZC0xIn0.eyJpYXQiOjE3MTIwNDc1NjUsInJvbGUiOiJhdXRoZW50aWNhdGVkIiwic3ViIjoidXNlci1pZCIsImV4cCI6MTcxMjA1MTE2NX0.zUeoZrWK1efAc4q9y978_9qkhdXktdjf5H8O9Rw0SHcPaXW8OBcuNR2huRrgORvqFx6_sHn6nCJaWkZGzO-f8wskMD7Z4INq2JUypr6nASie3Qu2lLyeY3WTInaXNAKH-oqlfTLRskbz8zkIxOj2bBJiN9ceQLkJU-c92ndiuiG5D1jyQrGsvRdFem_cemp0yOoEaC0XWdjeV6C_UD-34GIyv3o8H4HZg1GcCiyNnAfDmLAcTOQPmqkwsRDQb-pm5O3HwpQt9WHOB6i1vzf-nmIGyCRA7STPdALK16-aiAyT4SJRxM5WN3iK8yitH7g4JETb9WocBbwIM_zfNnUI5w" + + jwt_secret = "secret" + jwks = %{"keys" => [%{"kty" => "OKP", "kid" => "some_other_kid"}]} + + assert {:error, :error_generating_signer} = JwtVerification.verify(token, jwt_secret, jwks) + end end end