diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0ab4eba..4126607 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [ master ] + branches: [ main ] pull_request: - branches: [ master ] + branches: [ main ] jobs: check_duplicate_runs: @@ -36,12 +36,12 @@ jobs: fail-fast: false matrix: include: - - elixir: "1.10.4" - otp: "22.3" - - elixir: "1.12.2" - otp: "23.3" - elixir: "1.13.3" otp: "24.3" + - elixir: "1.14.3" + otp: "24.3" + - elixir: "1.14.3" + otp: "25.2" runs-on: ubuntu-latest @@ -103,7 +103,7 @@ jobs: MIX_ENV: test - name: Run tests - run: mix coveralls.github + run: mix coveralls.github --warnings-as-errors env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index eb0f732..e92dfd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -127,4 +127,4 @@ For changes on versions 1.x look on the v1.5 branch. ### Backwards incompatible changes - There is no `Joken.Plug` module anymore. Depending on requests we can bring that back, but we believe it is better to be on a different library; -- The API surface changed a lot but you can still use Joken with the same [token pattern as versions 1.x](http://trivelop.de/2018/05/14/flow-elixir-designing-apis/). Please see our [migrating guide](https://github.com/joken-elixir/joken/blob/master/guides/migration_from_1.md). +- The API surface changed a lot but you can still use Joken with the same [token pattern as versions 1.x](http://trivelop.de/2018/05/14/flow-elixir-designing-apis/). Please see our [migrating guide](https://github.com/joken-elixir/joken/blob/main/guides/migration_from_1.md). diff --git a/README.md b/README.md index 850360c..d6661fc 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # Joken -[![Build](https://travis-ci.org/joken-elixir/joken.svg?branch=master)](https://travis-ci.org/joken-elixir/joken) +[![Build](https://travis-ci.org/joken-elixir/joken.svg?branch=main)](https://travis-ci.org/joken-elixir/joken) [![Module Version](https://img.shields.io/hexpm/v/joken.svg)](https://hex.pm/packages/joken) [![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/joken/) [![Total Download](https://img.shields.io/hexpm/dt/joken.svg)](https://hex.pm/packages/joken) -[![License](https://img.shields.io/hexpm/l/joken.svg)](https://github.com/joken-elixir/joken/blob/master/LICENSE) -[![Last Updated](https://img.shields.io/github/last-commit/joken-elixir/joken.svg)](https://github.com/joken-elixir/joken/commits/master) +[![License](https://img.shields.io/hexpm/l/joken.svg)](https://github.com/joken-elixir/joken/blob/main/LICENSE) +[![Last Updated](https://img.shields.io/github/last-commit/joken-elixir/joken.svg)](https://github.com/joken-elixir/joken/commits/main) A JSON Web Token (JWT) Library. diff --git a/config/config.exs b/config/config.exs index 98f0a32..8294497 100644 --- a/config/config.exs +++ b/config/config.exs @@ -1,6 +1,6 @@ -use Mix.Config +import Config -case Mix.env() do +case config_env() do # Use the same key config as tests for benchmarking :bench -> import_config("test.exs") diff --git a/config/dev.exs b/config/dev.exs index ae2f5f8..edb23dd 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -1,3 +1,3 @@ -use Mix.Config +import Config config :joken, default_signer: "s3cr3t" diff --git a/config/prod.exs b/config/prod.exs index d2d855e..becde76 100644 --- a/config/prod.exs +++ b/config/prod.exs @@ -1 +1 @@ -use Mix.Config +import Config diff --git a/config/test.exs b/config/test.exs index 49db52d..44169f0 100644 --- a/config/test.exs +++ b/config/test.exs @@ -1,6 +1,6 @@ # This file is responsible for configuring your application # and its dependencies with the aid of the Mix.Config module. -use Mix.Config +import Config rsa_map_key = %{ "d" => diff --git a/guides/asymmetric_cryptography_signers.md b/guides/asymmetric_cryptography_signers.md index 774a606..9cf4897 100644 --- a/guides/asymmetric_cryptography_signers.md +++ b/guides/asymmetric_cryptography_signers.md @@ -70,7 +70,7 @@ Let's see some examples on parsing asymmetric RSA keys with Joken: This algorithm uses the RSASSA-PKCS1-v1_5 that uses SHA2 hash algorithms. The base for this algorithm is the RSA public key standard. So, to use this algorithm we need a pair of RSA keys. There are many ways to generate these keys in different environments and is outside the scope of this library. Here is one of these ways just for an example: ``` shell -➜ joken git:(master) openssl genrsa -out mykey.pem 4096 +➜ joken git:(main) openssl genrsa -out mykey.pem 4096 Generating RSA private key, 4096 bit long modulus (2 primes) .............++++ ...........................................................................................................++++ diff --git a/lib/joken/signer.ex b/lib/joken/signer.ex index 309e8df..38f3b99 100644 --- a/lib/joken/signer.ex +++ b/lib/joken/signer.ex @@ -75,7 +75,7 @@ defmodule Joken.Signer do def create(alg, secret, headers) when is_binary(secret) and alg in @hs_algorithms do raw_create( alg, - headers |> Map.merge(%{"alg" => alg, "typ" => "JWT"}) |> JWS.from_map(), + headers |> transform_headers(alg) |> JWS.from_map(), JWK.from_oct(secret) ) end @@ -86,7 +86,7 @@ defmodule Joken.Signer do def create(alg, %{"pem" => pem}, headers) when alg in @map_key_algorithms do raw_create( alg, - headers |> Map.merge(%{"alg" => alg, "typ" => "JWT"}) |> JWS.from_map(), + headers |> transform_headers(alg) |> JWS.from_map(), JWK.from_pem(pem) ) end @@ -94,7 +94,7 @@ defmodule Joken.Signer do def create(alg, key, headers) when is_map(key) and alg in @map_key_algorithms do raw_create( alg, - headers |> Map.merge(%{"alg" => alg, "typ" => "JWT"}) |> JWS.from_map(), + headers |> transform_headers(alg) |> JWS.from_map(), JWK.from_map(key) ) end @@ -239,17 +239,19 @@ defmodule Joken.Signer do {jwk_function, value} = List.first(key_config) if signer_alg in @algorithms do - do_parse_signer(jwk_function.(value), signer_alg, headers) + raw_create( + signer_alg, + headers |> transform_headers(signer_alg) |> JWS.from_map(), + jwk_function.(value) + ) else raise Joken.Error, :unrecognized_algorithm end end - defp do_parse_signer(jwk, signer_alg, headers) do - raw_create( - signer_alg, - headers |> Map.merge(%{"alg" => signer_alg, "typ" => "JWT"}) |> JWS.from_map(), - jwk - ) + defp transform_headers(headers, signer_alg) when is_map(headers) and is_binary(signer_alg) do + headers + |> Map.put("alg", signer_alg) + |> Map.put_new("typ", "JWT") end end diff --git a/mix.exs b/mix.exs index c8ee3d4..374dfeb 100644 --- a/mix.exs +++ b/mix.exs @@ -9,7 +9,7 @@ defmodule Joken.Mixfile do app: :joken, version: @version, name: "Joken", - elixir: "~> 1.10", + elixir: "~> 1.13", elixirc_paths: elixirc_paths(Mix.env()), start_permanent: Mix.env() == :prod, consolidate_protocols: Mix.env() != :test, @@ -56,7 +56,7 @@ defmodule Joken.Mixfile do # Test {:junit_formatter, "~> 3.1", only: :test}, {:stream_data, "~> 0.5", only: :test}, - {:excoveralls, "~> 0.14", only: :test} + {:excoveralls, "~> 0.15", only: :test} ] end diff --git a/mix.lock b/mix.lock index 1189143..8dcbbd2 100644 --- a/mix.lock +++ b/mix.lock @@ -5,13 +5,13 @@ "credo": {:hex, :credo, "1.6.7", "323f5734350fd23a456f2688b9430e7d517afb313fbd38671b8a4449798a7854", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "41e110bfb007f7eda7f897c10bf019ceab9a0b269ce79f015d54b0dcf4fc7dd3"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, "dialyxir": {:hex, :dialyxir, "1.2.0", "58344b3e87c2e7095304c81a9ae65cb68b613e28340690dfe1a5597fd08dec37", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "61072136427a851674cab81762be4dbeae7679f85b1272b6d25c3a839aff8463"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.26", "f4291134583f373c7d8755566122908eb9662df4c4b63caa66a0eabe06569b0a", [:mix], [], "hexpm", "48d460899f8a0c52c5470676611c01f64f3337bad0b26ddab43648428d94aabc"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.30", "0b938aa5b9bafd455056440cdaa2a79197ca5e693830b4a982beada840513c5f", [:mix], [], "hexpm", "3b5385c2d36b0473d0b206927b841343d25adb14f95f0110062506b300cd5a1b"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, - "ex_doc": {:hex, :ex_doc, "0.28.5", "3e52a6d2130ce74d096859e477b97080c156d0926701c13870a4e1f752363279", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "d2c4b07133113e9aa3e9ba27efb9088ba900e9e51caa383919676afdf09ab181"}, - "excoveralls": {:hex, :excoveralls, "0.15.1", "83c8cf7973dd9d1d853dce37a2fb98aaf29b564bf7d01866e409abf59dac2c0e", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f8416bd90c0082d56a2178cf46c837595a06575f70a5624f164a1ffe37de07e7"}, + "ex_doc": {:hex, :ex_doc, "0.29.1", "b1c652fa5f92ee9cf15c75271168027f92039b3877094290a75abcaac82a9f77", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "b7745fa6374a36daf484e2a2012274950e084815b936b1319aeebcf7809574f6"}, + "excoveralls": {:hex, :excoveralls, "0.15.3", "54bb54043e1cf5fe431eb3db36b25e8fd62cf3976666bafe491e3fa5e29eba47", [:mix], [{:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f8eb5d8134d84c327685f7bb8f1db4147f1363c3c9533928234e496e3070114e"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, - "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, - "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, + "hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~> 2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"}, + "idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, "jose": {:hex, :jose, "1.11.5", "3bc2d75ffa5e2c941ca93e5696b54978323191988eb8d225c2e663ddfefd515e", [:mix, :rebar3], [], "hexpm", "dcd3b215bafe02ea7c5b23dafd3eb8062a5cd8f2d904fd9caa323d37034ab384"}, "junit_formatter": {:hex, :junit_formatter, "3.3.1", "c729befb848f1b9571f317d2fefa648e9d4869befc4b2980daca7c1edc468e40", [:mix], [], "hexpm", "761fc5be4b4c15d8ba91a6dafde0b2c2ae6db9da7b8832a55b5a1deb524da72b"}, diff --git a/test/joken_signer_test.exs b/test/joken_signer_test.exs index a762ab2..5b856cb 100644 --- a/test/joken_signer_test.exs +++ b/test/joken_signer_test.exs @@ -121,6 +121,13 @@ defmodule Joken.Signer.Test do test "can parse with key_id" do {:ok, token, _claims} = Joken.encode_and_sign(%{}, Signer.parse_config(:with_key_id)) + assert {:ok, %{"kid" => "my_key_id", "alg" => "HS256"}} = Joken.peek_header(token) end + + test "can override typ header claim" do + signer = Signer.create("HS256", "secret", %{"typ" => "SOMETHING_ELSE"}) + {:ok, token, _claims} = Joken.encode_and_sign(%{}, signer) + assert {:ok, %{"typ" => "SOMETHING_ELSE"}} = Joken.peek_header(token) + end end diff --git a/test/joken_test.exs b/test/joken_test.exs index 1e3f7b1..7ab29f9 100644 --- a/test/joken_test.exs +++ b/test/joken_test.exs @@ -1,7 +1,7 @@ defmodule JokenTest do use ExUnit.Case, async: true import ExUnit.CaptureLog - import Joken.Config, only: [add_claim: 4, add_claim: 5, default_claims: 1] + import Joken.Config, only: [add_claim: 4, add_claim: 5] alias Joken.CurrentTime.Mock setup do