Giter VIP home page Giter VIP logo

elixir-jwt's Introduction

Yet another JWT lib for Elixir

This is a rewrite of json_web_token_ex with jwt_claims_ex merged in, both created by @garyf.

Many things were simplified during the rewrite, code was cleaned up as well.

Installation

The package can be installed by adding yajwt to your list of dependencies in mix.exs:

def deps do
  [{:yajwt, "~> 1.0"}]
end

Usage

JWT.sign(claims, options)

Returns a JSON Web Token string

claims (required) map

options (required) map

  • alg (optional, default: "HS256")
  • key (required unless alg is "none")

Include any JWS JOSE header parameters (RFC 7515) in the options map

Example

# sign with default algorithm, HMAC SHA256
jwt = JWT.sign(%{foo: "bar"}, %{key: "gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C"})

# sign with RSA SHA256 algorithm
private_key = JWT.Algorithm.RsaUtil.private_key("path/to/", "key.pem")
opts = %{
  alg: "RS256",
  key: private_key
}

jwt = JWT.sign(%{foo: "bar"}, opts)

# unsecured token (algorithm is "none")
jwt = JWT.sign(%{foo: "bar"}, %{alg: "none"})

JWT.verify(jwt, options)

Returns a tuple, either:

  • {:ok, claims}, a JWT claims set map, if the Message Authentication Code (MAC), or signature, is verified
  • {:error, exception}, otherwise

"jwt" (required) is a JSON web token string

options (required) map

  • alg (optional, default: "HS256")
  • key (required unless alg is "none")

Example

secure_jwt_example = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt.cGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"

# verify with default algorithm, HMAC SHA256
{:ok, claims} = JWT.verify(secure_jwt_example, %{key: "gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C"})

# Or with the bang version
claims = JWT.verify!(secure_jwt_example, %{key: "gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr9C"})

# verify with RSA SHA256 algorithm
opts = %{
  alg: "RS256",
  key: < RSA public key >
}

{:ok, claims} = JWT.verify(jwt, opts)

# unsecured token (algorithm is "none")
unsecured_jwt_example = "eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFt."

{:ok, claims} = JWT.verify(unsecured_jwt_example, %{alg: "none"})

Supported encryption algorithms

alg Param Value Digital Signature or MAC Algorithm
HS256 HMAC using SHA-256 per RFC 2104
HS384 HMAC using SHA-384
HS512 HMAC using SHA-512
RS256 RSASSA-PKCS-v1_5 using SHA-256 per RFC3447
RS384 RSASSA-PKCS-v1_5 using SHA-384
RS512 RSASSA-PKCS-v1_5 using SHA-512
ES256 ECDSA using P-256 and SHA-256 per DSS
ES384 ECDSA using P-384 and SHA-384
ES512 ECDSA using P-521 and SHA-512
none No digital signature or MAC performed (unsecured)

Registered claim names

The following claims are supported. They are validated when the JWT is verified.

  • iss (Issuer)
  • sub (Subject)
  • aud (Audience)
  • exp (Expiration Time)
  • nbf (Not Before)
  • iat (Issued At)
  • jti (JWT ID)

elixir-jwt's People

Contributors

dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar dvv avatar princemaple avatar renovate[bot] avatar teamon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

elixir-jwt's Issues

JWT.InvalidSignatureError from JWT.verify/2

I am trying to verify a JWT as a verifier, but followed the solution given here I still couldn't make it work.

My codes:

jwt = "eyJh....."
pem = JWT.Algorithm.RsaUtil.public_key(".", "public.pem")
IO.inspect(pem, label: "pem")
JWT.verify(jwt, %{
  alg: "RS256",
  key: pem
})

output:

pem: [65537,
237435391219...2230143]
{:error, JWT.InvalidSignatureError}

I am sure that my public.pem & jwt are valid.

Error on RSA JWT token verification

Given

token = "eyJhbGciOiJSUzI1NiIsImtpZCI6bnVsbH0.eyJpc3MiOiJlcGVyc29uYW0uY29tIiwic3ViIjoyNTQyLCJhdmEiOiIvL2VwZXJzb25hbS5zMy5ldS13ZXN0LTEuYW1hem9uYXdzLmNvbS91c2Vycy9hdmF0YXJzLzAwMC8wMDIvODU0L29yaWdpbmFsL1NjaGVybWF0YSAyMDE4LTA5LTA2IGFsbGUgMTYuMTQuNDgucG5nIiwiZm5hIjoiU2FsaWNldHRpIiwidW5hIjoia25pZ2h0cSIsImV4cCI6MTU1MTMxMTkxMSwianRpIjoiZTkyMTc0M2QtM2JjMy00N2U5LWI0ZDctNTMwNmNiNGI1ZmIwIn0.ukB_tFxBVQe2bx-3cbaPPwahPGdCydERsg_RWwxtPuJ4NYEW-z0o5-A4zFw9Ur8Ow6kx8RAUgtIQmBrNznaVgd4hKWhfySG8nbLAtdUYDMYghV9ZJO8u3sskjvMzil-9BpDtUj2zYxcjleLeGIxaJGDnfq88THGyiJ9hWvCQDIk6A6VzjQEzRI0svYvLxcpZthU1BHCLW2JOIHs-4_pqUOUXiVF9x5JZN2OirCogr7sI8UEkp9XDIaTzg6nEnfGbBqAHOGlijSW06BumNWa2-ilMP9z-tMVukuzB1wpVmftEaZV6qvBeYg4ISJ3q6dkEafgm9xHSbvVtU6RLhm2klQ"
opts = %{
  alg: "RS256",
  key: "-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8bp237rLGKRm0+2ZirUj
hNCtL/ZyHrINaXLBbDsz4eiw6imyEIQs1iFecAO5mGR/LxtNyHobyfHGipDFrIif
PKEsG7pfupJwpMpbnpc2m6k4WN56J2zCMzCClkR5EJ4OQJr0g5QDp1moA5OMfHg4
6ZCLqrrmJcz8kGX0jD54ElKEjWP9iw/BRYEJSHMyr9TCBAYoZVWetfrOqsbqtPPu
sM8v5NmsdrTBJeJhSZ0EQJ55+wzUdTCAaYIB1nr9nR0YBFETYc3FRFqabjY4rFam
qS4F9kwt/MbtAxaoTUOG7tf9Ci92z87rPz85O0aHkfnwvr3I8B1od6qq9DZPeDWZ
UwIDAQAB
-----END PUBLIC KEY-----
"
}
JWT.verify(token, opts)

I get this error:

** (FunctionClauseError) no function clause matching in JWT.Algorithm.Rsa.modulus/1

The following arguments were given to JWT.Algorithm.Rsa.modulus/1:

    # 1
    "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8bp237rLGKRm0+2ZirUj\nhNCtL/ZyHrINaXLBbDsz4eiw6imyEIQs1iFecAO5mGR/LxtNyHobyfHGipDFrIif\nPKEsG7pfupJwpMpbnpc2m6k4WN56J2zCMzCClkR5EJ4OQJr0g5QDp1moA5OMfHg4\n6ZCLqrrmJcz8kGX0jD54ElKEjWP9iw/BRYEJSHMyr9TCBAYoZVWetfrOqsbqtPPu\nsM8v5NmsdrTBJeJhSZ0EQJ55+wzUdTCAaYIB1nr9nR0YBFETYc3FRFqabjY4rFam\nqS4F9kwt/MbtAxaoTUOG7tf9Ci92z87rPz85O0aHkfnwvr3I8B1od6qq9DZPeDWZ\nUwIDAQAB\n-----END PUBLIC KEY-----\n"

Attempted function clauses (showing 1 out of 1):

    def modulus([_e, n | _d])

(yajwt) lib/jwt/algorithm/rsa.ex:45: JWT.Algorithm.Rsa.modulus/1
(yajwt) lib/jwt/algorithm/rsa.ex:49: JWT.Algorithm.Rsa.validate_key_size!/1
(yajwt) lib/jwt/algorithm/rsa.ex:40: JWT.Algorithm.Rsa.verify?/4
(yajwt) lib/jwt/jws.ex:95: JWT.Jws.verify_signature/3
(yajwt) lib/jwt/jws.ex:59: JWT.Jws.verify/3
(yajwt) lib/jwt.ex:79: JWT.verify/2

JWT with "sub" claim cannot be validated without knowing the sub

When I create a JWT with a sub and then try to verify it, I get an error. Surely it should be possible to verify a JWT with a sub without having to specify the sub?

iex(2)> JWT.verify(JWT.sign(%{"sub"=>"user"}, %{key: key}), %{key: key})
{:error, [sub: "user"]}
iex(3)> JWT.verify(JWT.sign(%{"sub"=>"user"}, %{key: key}), %{key: key, sub: "user"})
{:ok, %{"sub" => "user"}}

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

This repository currently has no open or pending branches.

Detected dependencies

github-actions
.github/workflows/elixir.yml
.github/workflows/publish-docs.yml
.github/workflows/publish.yml
.github/workflows/release.yml
  • release-drafter/release-drafter v6
mix
mix.exs
  • jason ~> 1.0
  • ex_doc >= 0.0.0

  • Check this box to trigger a request for Renovate to run again on this repository

Wrong documented return type from verify/2

@spec verify(binary, map) :: {:ok, map} | {:error, binary}

When a claim fails, it does not return binary, but a keyword list.

iex(1)> JWT.verify(JWT.sign(%{foo: "bar", exp: :os.system_time(:seconds) - 1}, key), key)
{:error, [exp: 1548504635]}

Duplicate module

Issue while using mix release

** (Mix) Duplicated modules:
	'Elixir.JWT.Algorithm.Hmac' specified in chirp and yajwt

here are my deps

 defp deps do
    [
      {:phoenix, "~> 1.4.11"},
      {:phoenix_pubsub, "~> 1.1"},
      {:phoenix_ecto, "~> 4.0"},
      {:ecto_sql, "~> 3.1"},
      {:postgrex, ">= 0.0.0"},
      {:phoenix_html, "~> 2.11"},
      {:phoenix_live_reload, "~> 1.2", only: :dev},
      {:gettext, "~> 0.11"},
      {:jason, "~> 1.0"},
      {:plug_cowboy, "~> 2.0"},
      {:slugify, "~> 1.2"},
      {:yajwt, "~> 1.2"},
      {:cors_plug, "~> 2.0"},
    ]
  end

How do we fix it ?

Passing garbage to verify/2 results in an exceptions rather than {:error, ...}

If I pass random strings to JWT.verify/2 I get exceptions rather than an error tuple

JWT.verify("this_is_a_bad_string", %{key: <my key>})

gives

     ** (Jason.DecodeError) unexpected byte at position 0: 0xB6
     code: |> VerifyAdmin.call(@plug)
     stacktrace:
       (jason) lib/jason.ex:78: Jason.decode!/2
       (yajwt) lib/jwt/jws.ex:84: JWT.Jws.validate_alg/2
       (yajwt) lib/jwt/jws.ex:58: JWT.Jws.verify/3
       (yajwt) lib/jwt.ex:79: JWT.verify/2
       (api_v1_web) lib/api_v1_web/jwt_helper.ex:8: ApiV1Web.JWTHelper.decode/1
       (api_v1_web) lib/api_v1_web/plugs/verify_admin.ex:16: ApiV1Web.Plugs.VerifyAdmin.call/2
       test/api_v1_web/plugs/verify_admin_test.exs:28: (test)

Similarly,

JWT.verify("this is a bad token", %{key: <my key>})

gives

     ** (ArgumentError) non-alphabet digit found: " " (byte 32)
     code: |> VerifyAdmin.call(@plug)
     stacktrace:
       (elixir) lib/base.ex:1002: Base.dec64url/1
       (elixir) lib/base.ex:1018: Base."-do_decode64url/2-lbc$^0/2-0-"/2
       (elixir) lib/base.ex:1012: Base.do_decode64url/2
       (yajwt) lib/jwt/coding.ex:10: JWT.Coding.decode!/2
       (yajwt) lib/jwt/jws.ex:84: JWT.Jws.validate_alg/2
       (yajwt) lib/jwt/jws.ex:58: JWT.Jws.verify/3
       (yajwt) lib/jwt.ex:79: JWT.verify/2
       (api_v1_web) lib/api_v1_web/jwt_helper.ex:8: ApiV1Web.JWTHelper.decode/1
       (api_v1_web) lib/api_v1_web/plugs/verify_admin.ex:16: ApiV1Web.Plugs.VerifyAdmin.call/2
       test/api_v1_web/plugs/verify_admin_test.exs:28: (test)

In both cases, these are not valid JWT tokens, but as we all know you get lots of random crap from users, so it would be useful for verify/2 (the non-bang) version to return {:error, <something>} rather than crashing.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.