Skip to content

Commit

Permalink
Merge pull request #12 from amezcua/develop
Browse files Browse the repository at this point in the history
v0.6.0
  • Loading branch information
amezcua authored Jan 11, 2017
2 parents 996ceff + a79c3ad commit 0df33ff
Show file tree
Hide file tree
Showing 16 changed files with 150 additions and 30 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

Elixir library that verifies Google generated JWT tokens (such as those returned by Firebase authentication) and returns the claims data.

The intended use case is to validate signed tokens retrieved by a mobile app using [Firebase Authentication](https://firebase.google.com/docs/auth/), where the app talks directly with the Google Authentication service and retrieves an authentication token (a Json Web Token) that can be later sent to a server for verification.
The intended use case is to validate signed tokens retrieved by a mobile app using [Firebase Authentication](https://firebase.google.com/docs/auth/), where the app talks directly with the Google Authentication service and retrieves an authentication token (a Json Web Token) that can be later sent to a server for verification or by web apps that use the Firebase [JavaScript API](https://firebase.google.com/docs/auth/web/google-signin).

JWT tokens are also returned by other Google authentication services and this library can be used to verify them too.
JWT tokens are also returned by other Google authentication services and this library could be used to verify them too.

## Usage

Expand All @@ -17,7 +17,7 @@ JWT tokens are also returned by other Google authentication services and this li

## Installation

The package can be installed as (will try to make it available in Hex in a future version):
The package can be installed as follows (will try to make it available in Hex in a future version):

1. Add `jwt` to your list of dependencies in `mix.exs`:

Expand Down
3 changes: 2 additions & 1 deletion config/dev.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ use Mix.Config

config :logger, level: :debug

config :jwt, :googlecerts, Jwt.GoogleCerts.PublicKey
config :jwt, :googlecerts, Jwt.GoogleCerts.PublicKey
config :jwt, :firebasecerts, Jwt.FirebaseCerts.PublicKey
3 changes: 2 additions & 1 deletion config/prod.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ use Mix.Config

config :logger, level: :debug

config :jwt, :googlecerts, Jwt.GoogleCerts.PublicKey
config :jwt, :googlecerts, Jwt.GoogleCerts.PublicKey
config :jwt, :firebasecerts, Jwt.FirebaseCerts.PublicKey
1 change: 1 addition & 0 deletions config/test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ use Mix.Config
config :logger, level: :debug

config :jwt, :googlecerts, Jwt.GoogleCerts.PublicKey.Mock
config :jwt, :firebasecerts, Jwt.FirebaseCerts.PublicKey.Mock
config :jwt, :timeutils, Jwt.TimeUtils.Mock
1 change: 0 additions & 1 deletion lib/etscache.ex
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ defmodule Jwt.Cache.Ets do

defp _get(uri) do
value = :ets.lookup(@cache_table_name, uri)
Logger.debug "#{inspect uri} -> #{inspect value}"
case value do
[] -> {:error, uri}
_ -> {:ok, elem(Enum.at(value, 0), 1)}
Expand Down
28 changes: 28 additions & 0 deletions lib/firebasecerts.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
defmodule Jwt.FirebaseCerts.PublicKey do

@httpclient Jwt.HttpCacheClient
@certs_url "https://www.googleapis.com/robot/v1/metadata/x509/[email protected]"

def getfor(id), do: fetch id

defp fetch(id) do
@httpclient.get!(@certs_url)
|> get_response_body
|> extract_public_key_for_id(id)
end

defp get_response_body(%{body: body, headers: _headers, status_code: 200}), do: {:ok, body}
defp get_response_body(%{body: body, headers: _headers, status_code: _status_code}), do: {:error, body}

defp extract_public_key_for_id({:error, _}, _id), do: nil
defp extract_public_key_for_id({:ok, body}, id) do
{:ok, parsed} = Poison.Parser.parse body

cert = parsed[id]

case cert do
nil -> {:error, "Public key id not found"}
cert_string -> Jwt.PemParser.extract_exponent_and_modulus_from_pem_cert cert_string
end
end
end
4 changes: 2 additions & 2 deletions lib/googlecerts.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ defmodule Jwt.GoogleCerts.PublicKey do
defp extract_certificated_url({:ok, body}) do
{:ok, parsed} = Poison.Parser.parse body
case parsed[@jwt_uri_in_discovery] do
nil -> {:error, "No JWT url found"}
nil -> {:notfounderror, "No JWT url found"}
_ -> {:ok, parsed[@jwt_uri_in_discovery]}
end
end
Expand All @@ -46,7 +46,7 @@ defmodule Jwt.GoogleCerts.PublicKey do
key = List.first(Enum.filter parsed["keys"], fn key -> key["kid"] == id end)

case key do
nil -> {:error, "Public key id not found"}
nil -> {:notfounderror, "Public key id not found"}
_ -> {:ok, %{exp: key[@exponent], mod: key[@modulus]}}
end
end
Expand Down
28 changes: 20 additions & 8 deletions lib/jwt.ex
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
defmodule Jwt do
@google_certs_api Application.get_env(:jwt, :googlecerts, Jwt.GoogleCerts.PublicKey)
@firebase_certs_api Application.get_env(:jwt, :firebasecerts, Jwt.FirebaseCerts.PublicKey)
@invalid_token_error {:error, "Invalid token"}
@invalid_signature_error {:error, "Invalid signature"}
@key_id "kid"
@alg "alg"

@doc """
Verifies a Google generated JWT token against the current public Google certificates and returns the claims
Verifies a Google or Firebase generated JWT token against the current public certificates and returns the claims
if the token's signature is verified successfully.
## Example
iex > {:ok, {claims}} = Jwt.verify token
{:ok, {claims}} = Jwt.verify token
"""
def verify(token) do
token_parts = String.split token, "."
Expand All @@ -19,23 +20,34 @@ defmodule Jwt do
end

defp _verify([{:ok, header}, {:ok, _claims}, {:ok, signature}], [header_b64, claims_b64, _signature_b64]) do
Poison.Parser.parse!(header)[@key_id]
|> @google_certs_api.getfor
header
|> extract_key_id
|> retrieve_cert_exp_and_mod_for_key
|> verify_signature(header_b64, claims_b64, signature)
end

defp _verify(_,_), do: @invalid_token_error

defp verify_signature({:ok, public_key}, header_b64, claims_b64, signature) do
defp extract_key_id(header), do: Poison.Parser.parse!(header)[@key_id]

defp retrieve_cert_exp_and_mod_for_key(key_id) do
@google_certs_api.getfor(key_id)
|> case do
{:ok, cert_data} -> {:ok, cert_data}
{:notfounderror, _} -> @firebase_certs_api.getfor(key_id)
_ -> @invalid_token_error
end
end

defp verify_signature({:ok, %{exp: exponent, mod: modulus}}, header_b64, claims_b64, signature) do
msg = header_b64 <> "." <> claims_b64
mod = :binary.decode_unsigned(Base.url_decode64!(public_key.mod, padding: false))
exp = :binary.decode_unsigned(Base.url_decode64!(public_key.exp, padding: false))

case :crypto.verify :rsa, :sha256, msg, signature, [exp, mod] do
case :crypto.verify :rsa, :sha256, msg, signature, [exponent, modulus] do
true -> {:ok, Poison.Parser.parse! Base.url_decode64!(claims_b64, padding: false)}
false -> @invalid_signature_error
end
end

defp verify_signature({:error, _}, _, _, _), do: @invalid_token_error
defp verify_signature(_, _, _, _), do: @invalid_signature_error
end
20 changes: 20 additions & 0 deletions lib/pemparser.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
defmodule Jwt.PemParser do
def extract_exponent_and_modulus_from_pem_cert(pem_cert) do
[{_, dert, _}] = :public_key.pem_decode(pem_cert)
otp = :public_key.pkix_decode_cert(dert, :otp)

[_, mod, exp] = otp
|> Tuple.to_list
|> Enum.slice(1..1)
|> hd
|> Tuple.to_list
|> Enum.slice(7..7)
|> hd
|> Tuple.to_list
|> Enum.slice(2..2)
|> hd
|> Tuple.to_list

{:ok, %{exp: exp, mod: mod}}
end
end
6 changes: 5 additions & 1 deletion lib/plug.ex
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,9 @@ defmodule Jwt.Plug do
defp continue_if_verified({:ok, claims}, conn) do
assign(conn, :jwtclaims, claims)
end
defp continue_if_verified({:error, _}, conn), do: send_resp(conn, 401, "")
defp continue_if_verified({:error, _}, conn) do
conn
|> send_resp(401, "")
|> halt
end
end
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ defmodule Jwt.Mixfile do

def project do
[app: :jwt,
version: "0.5.0",
version: "0.6.0",
elixir: "~> 1.3",
elixirc_paths: elixirc_paths(Mix.env),
build_embedded: Mix.env == :prod,
Expand Down
34 changes: 34 additions & 0 deletions test/firebase_certs_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
defmodule FirebaseCertsTest do
use ExUnit.Case, async: true

require Logger

@certificate "-----BEGIN CERTIFICATE-----\nMIIDHDCCAgSgAwIBAgIIHCf0ZvzSh6gwDQYJKoZIhvcNAQEFBQAwMTEvMC0GA1UE\nAxMmc2VjdXJldG9rZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wHhcNMTcw\nMTAzMDA0NTI2WhcNMTcwMTA2MDExNTI2WjAxMS8wLQYDVQQDEyZzZWN1cmV0b2tl\nbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBAMew823wkK4hu02ROzImYBkryY8V6hH5aKbIcbXoaktTn/en\n5PB29MFqgy5GXrPsg6knIxsx2RR+yX5qWvMJJlxYz/NytMNkgFZPh+wtgEG0XmA5\n34J1nS6p9Lg/5jgxTyDmN9/WOj9Ml4DgQSFzz4f4AGwStw+dOERXBz+wASrs+8qL\ntxLt/Z2ENAqMDnxaY8VdOqNlFeQuBca3KQsZEvv3jObFGwrtFsCa+gnQ2JNYCACz\nuaJou68I4P0SOc17NqX8NZtyW/UmBam2WEHfE9C8qGUk96sfIktSL5MwRYQyl3UP\nU+SiorVkGBJgTGMHSymsbR/Ia4tB+nQ4KIuEbWUCAwEAAaM4MDYwDAYDVR0TAQH/\nBAIwADAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJ\nKoZIhvcNAQEFBQADggEBAJ3M+1HJTt/IQZ/09eW8B9gwgBBVhawZ1n0+aY7SuKSB\njHz474nUlQVz6SxBmeVScb9IXh2lL1K+YYrP/O7sP/OUYXHfjxKGNFMDl/lo/Pgq\nMmSOXnvbvEOgXrsgF8/ytj2BEyMe7wuZC7impUCkbarV4FKcvqjff1iLzAKWn4et\nRJJEyEngemOfAl2l9JBuQG/mouOyapv1g7B9mfRTTYKtbFl1o3N1GJtWC78pD+K9\noawYyz9tiGmm8IKW/KYiJhj616eq06ugEb3VHDjFL+hjGPmORPUND/al+XibYU/q\nNN45J+dag1ZeKxu1Ugc9p2IQB1RMtLMfGmaBldHQ5dY=\n-----END CERTIFICATE-----\n"

@header "eyJhbGciOiJSUzI1NiIsImtpZCI6ImU3MGRiMDg5MzU5MDBkNTY0YWFiMjdiMzllNmJkNWM4NDdkMDQxM2QifQ"
@claims "eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vYmFkYWNoaW4tNTUzYjkiLCJuYW1lIjoiQWxlamFuZHJvIE1lemN1YSIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vLWZJSlQ3RzJ1WjNFL0FBQUFBQUFBQUFJL0FBQUFBQUFBQVFZL0p2Q1ZtRkhYbnI4L3Bob3RvLmpwZyIsImF1ZCI6ImJhZGFjaGluLTU1M2I5IiwiYXV0aF90aW1lIjoxNDgzMzUxNjY5LCJ1c2VyX2lkIjoiTVNsZ0JueVU1NWdRQ3Q3WElTNWpiQzVYdE5BMyIsInN1YiI6Ik1TbGdCbnlVNTVnUUN0N1hJUzVqYkM1WHROQTMiLCJpYXQiOjE0ODM0MjkzMzYsImV4cCI6MTQ4MzQzMjkzNiwiZW1haWwiOiJhbGVqYW5kcm8ubWV6Y3VhQGJ5dGVhYnl0ZS5uZXQiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJnb29nbGUuY29tIjpbIjExMDM2MTQwMDI0NDg3MTIyNTQxNCJdLCJlbWFpbCI6WyJhbGVqYW5kcm8ubWV6Y3VhQGJ5dGVhYnl0ZS5uZXQiXX0sInNpZ25faW5fcHJvdmlkZXIiOiJnb29nbGUuY29tIn19"
@signature "tk8mTHJnRCqn1KQ0Ha5R_34sOWYoxV0QFCgLQ32UCLWy00kkq_waLyoYdb7G7Tns6dLk6e2rPcrz97JCcWTCqD3erMd9oN2IyqAGPUOU7FJr8PjtaMzHWDUdTinI05sKpRJNxMcEiP7Wd0VKk4ubuImbO7MphKZL5-KLz2KTcQztQaJC0dw1Ey3mBCSbdOkIMuTxCzfjkvXrbmGirIAfn8INJyIEg8Vnav-NaBT5ShIcie_ovVZy97iReNcubRZn34ipMQrai_k_JaRjlVMn0m0u9dee44S4XHlvdC4hkC-DpBZubDDj3BVQq-Ztk9H9CZREuPUjdfy3anflBE_BwQ"

test "Verify signature Firebase certificate" do
[{_, dert, _}] = :public_key.pem_decode(@certificate)
otp = :public_key.pkix_decode_cert(dert, :otp)

[_, mod, exp] = otp
|> Tuple.to_list
|> Enum.slice(1..1)
|> hd
|> Tuple.to_list
|> Enum.slice(7..7)
|> hd
|> Tuple.to_list
|> Enum.slice(2..2)
|> hd
|> Tuple.to_list

pk = [exp, mod]
signature = Base.url_decode64! @signature, padding: false
msg = @header <> "." <> @claims

assert :crypto.verify :rsa, :sha256, msg, signature, pk
end
end
4 changes: 2 additions & 2 deletions test/certs_test.exs → test/google_certs_test.exs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule CertsTest do
defmodule GoogleCertsTest do
use ExUnit.Case, async: true

@mod "zkSRsA8npcga4dKSt91-OtSXA481Y94jt5tn64h2MUtUnQ_1JP-4xcDBYVG52m1Cdc7Fq2_cpUOvm27jAxIc4oYxLk1YtyJX9ce5p2rkbKyC71nSq5om3rBE4n3hYUa0nPCcXNC0uC_G0UTVY_OsiYS6hSNVSnHqySn50yid8EBWY8sHHCsqEtlk4uwXXalgnpZ5BXI22yQWQASnZdeIiRKhxSWdkDrbLUq1FmyfNn9vabhIADZsdjCL3iCfJVW8YTdntObZRVsuh_ezm9K7-l3U400EvZA7RN_Dt5QGC6gSjo4syP5TkGXD6iC6rUx67FLzgww_Lo0O4kYEFzDLzw"
Expand All @@ -7,7 +7,7 @@ defmodule CertsTest do
@claims "eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhdWQiOiIzNDczODQ1NjIxMTMtcmRtNnNsZG0xbWIzOGs0dW1yY28zcDhsN3I1aGcwazUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTAzNjE0MDAyNDQ4NzEyMjU0MTQiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXpwIjoiMzQ3Mzg0NTYyMTEzLXIyOHBqZDB1Yzlwb2Y1Y20xcDBubmwyNXM5N2o4dXFwLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiaGQiOiJieXRlYWJ5dGUubmV0IiwiZW1haWwiOiJhbGVqYW5kcm8ubWV6Y3VhQGJ5dGVhYnl0ZS5uZXQiLCJpYXQiOjE0NzMyMjU4NjQsImV4cCI6MTQ3MzIyOTQ2NCwibmFtZSI6IkFsZWphbmRybyBNZXpjdWEiLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1mSUpUN0cydVozRS9BQUFBQUFBQUFBSS9BQUFBQUFBQUFRWS9KdkNWbUZIWG5yOC9zOTYtYy9waG90by5qcGciLCJnaXZlbl9uYW1lIjoiQWxlamFuZHJvIiwiZmFtaWx5X25hbWUiOiJNZXpjdWEiLCJsb2NhbGUiOiJlbiJ9"
@signature "Kc90u_gtZyhq6glw6UoYQSInZx9r16uqrRO7g50x17JWH7VkyAZrh3sfjdBYpGtDNJjDRBKSxuinpDjpyfiCp3-XAqqOUWqziyYvkV4-CdQvNhcnUQFXjjx_CzNiiEi5PRPCHhX4ajidet1NH4Me02S17gwOZiaZfed1BMWQuQ_7Hf2RsX5FID1xqOpcaaouMFcrqQFmdBIbcstHamWxs9D83c4JpOsioNOMb6-LBinzOg7qdxr1D4NvHD6VSXBTbyXiOBjK2elLU1iCz_Hz_BH-R1IYCdTRr5PczRWdSCgoTdZ7ds1nTTglfuXlGNbaEhhzsFxX8OCR4uNK6vbWXQ"

test "Verify signature" do
test "Verify signature Google certificate" do
mod = :binary.decode_unsigned(Base.url_decode64!(@mod, padding: false))
exp = :binary.decode_unsigned(Base.url_decode64!(@exp, padding: false))
pk = [exp, mod]
Expand Down
23 changes: 15 additions & 8 deletions test/jwt_test.exs
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
defmodule JwtTest do
use ExUnit.Case, async: true
doctest Jwt

@google_certs_api Application.get_env(:jwt, :googlecerts)
@invalid_token_error {:error, "Invalid token"}
@base64part "eyJhbGciOiJSUzI1NiIsImtpZCI6IjdkMWEzMTcxMTE5NTFiZDI0MjdlMjZmMjA3Nzc3MzRlYjgwZjY1YTUifQ"
@non_base64part "1"
@valid_token_header "eyJhbGciOiJSUzI1NiIsImtpZCI6IjEwZWZiZjlmOWEzZThlYzVlN2RmYTc5NjFkNzFlMmU0YmZkYTI0MzUifQ"
@valid_token_claims "eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhdWQiOiIzNDczODQ1NjIxMTMtcmRtNnNsZG0xbWIzOGs0dW1yY28zcDhsN3I1aGcwazUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTAzNjE0MDAyNDQ4NzEyMjU0MTQiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXpwIjoiMzQ3Mzg0NTYyMTEzLXIyOHBqZDB1Yzlwb2Y1Y20xcDBubmwyNXM5N2o4dXFwLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiaGQiOiJieXRlYWJ5dGUubmV0IiwiZW1haWwiOiJhbGVqYW5kcm8ubWV6Y3VhQGJ5dGVhYnl0ZS5uZXQiLCJpYXQiOjE0NzMyMjU4NjQsImV4cCI6MTQ3MzIyOTQ2NCwibmFtZSI6IkFsZWphbmRybyBNZXpjdWEiLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1mSUpUN0cydVozRS9BQUFBQUFBQUFBSS9BQUFBQUFBQUFRWS9KdkNWbUZIWG5yOC9zOTYtYy9waG90by5qcGciLCJnaXZlbl9uYW1lIjoiQWxlamFuZHJvIiwiZmFtaWx5X25hbWUiOiJNZXpjdWEiLCJsb2NhbGUiOiJlbiJ9"
@valid_token_signature "Kc90u_gtZyhq6glw6UoYQSInZx9r16uqrRO7g50x17JWH7VkyAZrh3sfjdBYpGtDNJjDRBKSxuinpDjpyfiCp3-XAqqOUWqziyYvkV4-CdQvNhcnUQFXjjx_CzNiiEi5PRPCHhX4ajidet1NH4Me02S17gwOZiaZfed1BMWQuQ_7Hf2RsX5FID1xqOpcaaouMFcrqQFmdBIbcstHamWxs9D83c4JpOsioNOMb6-LBinzOg7qdxr1D4NvHD6VSXBTbyXiOBjK2elLU1iCz_Hz_BH-R1IYCdTRr5PczRWdSCgoTdZ7ds1nTTglfuXlGNbaEhhzsFxX8OCR4uNK6vbWXQ"
@valid_google_token_header "eyJhbGciOiJSUzI1NiIsImtpZCI6IjEwZWZiZjlmOWEzZThlYzVlN2RmYTc5NjFkNzFlMmU0YmZkYTI0MzUifQ"
@valid_google_token_claims "eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhdWQiOiIzNDczODQ1NjIxMTMtcmRtNnNsZG0xbWIzOGs0dW1yY28zcDhsN3I1aGcwazUuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMTAzNjE0MDAyNDQ4NzEyMjU0MTQiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXpwIjoiMzQ3Mzg0NTYyMTEzLXIyOHBqZDB1Yzlwb2Y1Y20xcDBubmwyNXM5N2o4dXFwLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwiaGQiOiJieXRlYWJ5dGUubmV0IiwiZW1haWwiOiJhbGVqYW5kcm8ubWV6Y3VhQGJ5dGVhYnl0ZS5uZXQiLCJpYXQiOjE0NzMyMjU4NjQsImV4cCI6MTQ3MzIyOTQ2NCwibmFtZSI6IkFsZWphbmRybyBNZXpjdWEiLCJwaWN0dXJlIjoiaHR0cHM6Ly9saDMuZ29vZ2xldXNlcmNvbnRlbnQuY29tLy1mSUpUN0cydVozRS9BQUFBQUFBQUFBSS9BQUFBQUFBQUFRWS9KdkNWbUZIWG5yOC9zOTYtYy9waG90by5qcGciLCJnaXZlbl9uYW1lIjoiQWxlamFuZHJvIiwiZmFtaWx5X25hbWUiOiJNZXpjdWEiLCJsb2NhbGUiOiJlbiJ9"
@valid_google_token_signature "Kc90u_gtZyhq6glw6UoYQSInZx9r16uqrRO7g50x17JWH7VkyAZrh3sfjdBYpGtDNJjDRBKSxuinpDjpyfiCp3-XAqqOUWqziyYvkV4-CdQvNhcnUQFXjjx_CzNiiEi5PRPCHhX4ajidet1NH4Me02S17gwOZiaZfed1BMWQuQ_7Hf2RsX5FID1xqOpcaaouMFcrqQFmdBIbcstHamWxs9D83c4JpOsioNOMb6-LBinzOg7qdxr1D4NvHD6VSXBTbyXiOBjK2elLU1iCz_Hz_BH-R1IYCdTRr5PczRWdSCgoTdZ7ds1nTTglfuXlGNbaEhhzsFxX8OCR4uNK6vbWXQ"

@valid_firebase_token_header "eyJhbGciOiJSUzI1NiIsImtpZCI6ImU3MGRiMDg5MzU5MDBkNTY0YWFiMjdiMzllNmJkNWM4NDdkMDQxM2QifQ"
@valid_firebase_token_claims "eyJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vYmFkYWNoaW4tNTUzYjkiLCJuYW1lIjoiQWxlamFuZHJvIE1lemN1YSIsInBpY3R1cmUiOiJodHRwczovL2xoMy5nb29nbGV1c2VyY29udGVudC5jb20vLWZJSlQ3RzJ1WjNFL0FBQUFBQUFBQUFJL0FBQUFBQUFBQVFZL0p2Q1ZtRkhYbnI4L3Bob3RvLmpwZyIsImF1ZCI6ImJhZGFjaGluLTU1M2I5IiwiYXV0aF90aW1lIjoxNDgzMzUxNjY5LCJ1c2VyX2lkIjoiTVNsZ0JueVU1NWdRQ3Q3WElTNWpiQzVYdE5BMyIsInN1YiI6Ik1TbGdCbnlVNTVnUUN0N1hJUzVqYkM1WHROQTMiLCJpYXQiOjE0ODM0MjkzMzYsImV4cCI6MTQ4MzQzMjkzNiwiZW1haWwiOiJhbGVqYW5kcm8ubWV6Y3VhQGJ5dGVhYnl0ZS5uZXQiLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJnb29nbGUuY29tIjpbIjExMDM2MTQwMDI0NDg3MTIyNTQxNCJdLCJlbWFpbCI6WyJhbGVqYW5kcm8ubWV6Y3VhQGJ5dGVhYnl0ZS5uZXQiXX0sInNpZ25faW5fcHJvdmlkZXIiOiJnb29nbGUuY29tIn19"
@valid_firebase_token_signature "tk8mTHJnRCqn1KQ0Ha5R_34sOWYoxV0QFCgLQ32UCLWy00kkq_waLyoYdb7G7Tns6dLk6e2rPcrz97JCcWTCqD3erMd9oN2IyqAGPUOU7FJr8PjtaMzHWDUdTinI05sKpRJNxMcEiP7Wd0VKk4ubuImbO7MphKZL5-KLz2KTcQztQaJC0dw1Ey3mBCSbdOkIMuTxCzfjkvXrbmGirIAfn8INJyIEg8Vnav-NaBT5ShIcie_ovVZy97iReNcubRZn34ipMQrai_k_JaRjlVMn0m0u9dee44S4XHlvdC4hkC-DpBZubDDj3BVQq-Ztk9H9CZREuPUjdfy3anflBE_BwQ"

test "Invalid Jwt tokens are rejected" do
invalid_token = "invalid_token"
Expand Down Expand Up @@ -36,9 +38,14 @@ defmodule JwtTest do
assert @invalid_token_error = Jwt.verify(invalid_token)
end

test "The claims are extracted from a valid token" do
valid_token = @valid_token_header <> "." <> @valid_token_claims <> "." <> @valid_token_signature
assert {:ok, _} = Jwt.verify(valid_token)
test "The claims are extracted from a valid Google token" do
valid_google_token = @valid_google_token_header <> "." <> @valid_google_token_claims <> "." <> @valid_google_token_signature
assert {:ok, _} = Jwt.verify(valid_google_token)
end

test "The claims are extracted from a valid Firebase token" do
valid_firebase_token = @valid_firebase_token_header <> "." <> @valid_firebase_token_claims <> "." <> @valid_firebase_token_signature
assert {:ok, _} = Jwt.verify(valid_firebase_token)
end

end
9 changes: 9 additions & 0 deletions test/support/firebasecertsmock.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
defmodule Jwt.FirebaseCerts.PublicKey.Mock do
require Logger

@certificate "-----BEGIN CERTIFICATE-----\nMIIDHDCCAgSgAwIBAgIIHCf0ZvzSh6gwDQYJKoZIhvcNAQEFBQAwMTEvMC0GA1UE\nAxMmc2VjdXJldG9rZW4uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wHhcNMTcw\nMTAzMDA0NTI2WhcNMTcwMTA2MDExNTI2WjAxMS8wLQYDVQQDEyZzZWN1cmV0b2tl\nbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD\nggEPADCCAQoCggEBAMew823wkK4hu02ROzImYBkryY8V6hH5aKbIcbXoaktTn/en\n5PB29MFqgy5GXrPsg6knIxsx2RR+yX5qWvMJJlxYz/NytMNkgFZPh+wtgEG0XmA5\n34J1nS6p9Lg/5jgxTyDmN9/WOj9Ml4DgQSFzz4f4AGwStw+dOERXBz+wASrs+8qL\ntxLt/Z2ENAqMDnxaY8VdOqNlFeQuBca3KQsZEvv3jObFGwrtFsCa+gnQ2JNYCACz\nuaJou68I4P0SOc17NqX8NZtyW/UmBam2WEHfE9C8qGUk96sfIktSL5MwRYQyl3UP\nU+SiorVkGBJgTGMHSymsbR/Ia4tB+nQ4KIuEbWUCAwEAAaM4MDYwDAYDVR0TAQH/\nBAIwADAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwIwDQYJ\nKoZIhvcNAQEFBQADggEBAJ3M+1HJTt/IQZ/09eW8B9gwgBBVhawZ1n0+aY7SuKSB\njHz474nUlQVz6SxBmeVScb9IXh2lL1K+YYrP/O7sP/OUYXHfjxKGNFMDl/lo/Pgq\nMmSOXnvbvEOgXrsgF8/ytj2BEyMe7wuZC7impUCkbarV4FKcvqjff1iLzAKWn4et\nRJJEyEngemOfAl2l9JBuQG/mouOyapv1g7B9mfRTTYKtbFl1o3N1GJtWC78pD+K9\noawYyz9tiGmm8IKW/KYiJhj616eq06ugEb3VHDjFL+hjGPmORPUND/al+XibYU/q\nNN45J+dag1ZeKxu1Ugc9p2IQB1RMtLMfGmaBldHQ5dY=\n-----END CERTIFICATE-----\n"

def getfor(id) do
Jwt.PemParser.extract_exponent_and_modulus_from_pem_cert @certificate
end
end
Loading

0 comments on commit 0df33ff

Please sign in to comment.