fireproofsocks
Using Joken to validate Google JWTs
I’ve been trying out the Joken package to work with JWTs. Right now I’m unable to verify the JWTs that Google generates during Oauth. Has anyone implemented this? I think Joken has all the pieces, I just can’t figure out the winning combination. I’ve been reading this: Authenticate with a backend server | Web guides | Google for Developers
Google’s public keys are available in JWK format https://www.googleapis.com/oauth2/v3/certs
and in PEM format: https://www.googleapis.com/oauth2/v1/certs
I can get Google JWT, and I’ve tried to set up a module for these particular Google JWTs:
defmodule GoogleJwt do
use Joken.Config, default_signer: nil # no signer
def token_config do
default_claims()
end
end
But the following always generates an error of invalid signature:
MyGoogleJwt.verify_and_validate(idtoken)
Anyone have any tips?
Most Liked
vinagrito1
Heya guys. So I’m another soul that struggled with something that was supposed to be much easier for a while. And finally landed here.
So after trying all the libraries out there I’m sticking to JOSE. Thx @dom for mentioning it. As @fireproofsocks pointed out previously
I can run something like:
token = "from google oauth"
pem = "--- relevant key copied from https://www.googleapis.com/oauth2/v1/certs"
jwk = JOSE.JWK.from_pem(pem)
JOSE.JWT.verify_strict(jwk, ["RS256"], token)
Will do the job. Thank you all for the inputs
victorolinasc
Sorry for such a delayed response. I’ve replied @fireproofsocks on Joken repo about RS keys configuration and released a more detailed configuration of asymmetric keys guide.
To validate tokens from Google, Microsoft and other that have an OpenID Connect certs endpoint (or similar) with a published JWKS, one can use JokenJwks.
You’d do simply:
defmodule MyGoogleToken do
use Joken.Config
add_hook(JokenJwks, strategy: MyGoogleStrategy)
def token_config do
# your config here with what you want to validate from the token
end
end
defmodule MyGoogleJwksStrategy do
use JokenJwks.DefaultStrategyTemplate
def init_opts(opts), do: [jwks_url: "https://www.googleapis.com/oauth2/v1/certs"]
end
defmodule MyApp do
use Application
def start(_type, _args) do
children =
[
MyGoogleStrategy,
# others
]
# other start logic
end
spencerdcarlson
If you are just interested in using Google’s certs to validate a JWT issued by them, I made the google_certs hex package.
The Google Certs package will download, cache, and auto refresh Google’s certs. Both v1 PEM format and v3 JWK format are supported and are ready to work with Joken (see GoogleCerts.fetch/1). Here is the example from the how to use with joken section in the docs:
defmodule MyApp.Application do
@moduledoc false
use Application
alias GoogleCerts.CertificateCache
def start(_type, _args) do
children = [
CertificateCache
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor]
Supervisor.start_link(children, opts)
end
end
defmodule MyApp.Crypto.VerifyHook do
@moduledoc false
use Joken.Hooks
@impl true
def before_verify(_options, {jwt, %Joken.Signer{} = _signer}) do
with {:ok, %{"kid" => kid}} <- Joken.peek_header(jwt),
{:ok, algorithm, key} <- GoogleCerts.fetch(kid) do
{:cont, {jwt, Joken.Signer.create(algorithm, key)}}
else
error -> {:halt, {:error, :no_signer}}
end
end
end
defmodule MyApp.Crypto.JWTManager do
@moduledoc false
use Joken.Config, default_signer: nil
@iss "https://accounts.google.com"
# your google client id (usually ends in *.apps.googleusercontent.com)
defp aud, do: Application.get_env(:my_app, :google_client_id)
# reference your custom verify hook here
add_hook(MyApp.Crypto.VerifyHook)
@impl Joken.Config
def token_config do
default_claims(skip: [:aud, :iss])
|> add_claim("iss", nil, &(&1 == @iss))
|> add_claim("aud", nil, &(&1 == aud()))
end
end
# anywhere in your app you can verify and validate a Google issued JWT
iex> jwt = "eyJhbGciOiJSUzI1..." # Google issued JWT (api call, uberauth, etc)
iex> {:ok, claims} = JWTManager.verify_and_validate(jwt)
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex










