Phoenix and Auth0

Hi there,

I have an Elm frontend app, performing user login and token creation with Auth0 Lock, and then performing requests to a Phoenix API on the backend, passing the JWT token from Elm to Phoenix in an "Authorization: Bearer " header.

I want the Phoenix API to be able to verify the supplied token in order to auth the request from the client app.

I’m currently using Guardian(https://hexdocs.pm/guardian/api-reference.html), configured along these lines:
https://github.com/ueberauth/guardian/issues/211

I’m new to Phoenix.
I can’t get past ‘plug Guardian.Plug.EnsureAuthenticated’.
I’m not sure how to debug/inspect router/pipeline.
Ideally, I’d like Guardian.Plug.EnsureAuthenticated to reside in the pipeline, rather than in each controller.

Am I correct in assuming that Guardian will actually verify the supplied token with Auth0?
Because there doesn’t seem to be any provision in the config for the Auth0 ‘client_id’, which I expect would be necessary.

4 Likes

How do you pass in the request from front-end the JWT token?

3 Likes

I’m adding a header (Authorization: Bearer <token>) to the request.
I understand Guardian should find and verify this token with the plug Guardian.Plug.VerifyHeader, realm: "Bearer" in the pipeline. I’m using the same Auth0 secret in the config for both client and server.

2 Likes

Ok, from this what you are saying everything sounds fine. I guess you need provide some code examples, so maybe then I could check out it and give you feedback.

1 Like

Okay - here’s my code. Let me know if I’ve missed anything out.

config.exs

# Configures Guardian
config :guardian, Guardian,
  allowed_algos: ["HS256"],
  verify_module: Guardian.JWT,
  issuer: <Auth0 domain, same as is used client-side>,
  verify_issuer: true,
  secret_key: <Auth0 client secret, same as is used client-side for token generation>,
  serializer: MyApp.GuardianSerializer

###router.ex

  # pipeline for api
  pipeline :api do
    plug :accepts, ["json"]
    plug Guardian.Plug.VerifyHeader, realm: "Bearer "
    plug Guardian.Plug.EnsureAuthenticated
    plug Guardian.Plug.LoadResource
  end

Serializer

defmodule MyApp.GuardianSerializer do
  @behaviour Guardian.Serializer
  def for_token(id), do: {:ok, id}
  def from_token(id), do: {:ok, id}
end
1 Like

For me, this looks like this plug Guardian.Plug.VerifyHeader, realm: "Bearer"

And Serializer like this

defmodule MyApp.GuardianSerializer do
  @behaviour Guardian.Serializer

  alias MyApp.Repo
  alias MyApp.User

  def for_token(account = %User{}), do: { :ok, "Account:#{account.id}" }
  def for_token(_), do: { :error, "Unknown resource type" }

  def from_token("Account:" <> id), do: { :ok, Repo.get(User, id) }
  def from_token(_), do: { :error, "Unknown resource type" }
end
1 Like

I currently don’t have Ecto or a Repo set up - not sure I’ll need one, since this API is going to talk straight to another third-party API, so the Serializer isn’t really required, in my case.

I’m still not getting past the VerifyHeader plug - EnsureAuthenticated is failing.
I’m thinking my issue is around the Guardian config. I’m wondering if I’m missing something.

1 Like

Was on a project recently with auth0 and guardian and got it to work. I think maybe try setting verify_issuer to false

1 Like

I started from the beginning, setting up Guardian from scratch, and it worked.
I’m still not clear why it wasn’t working in the first instance.

If anyone is interested, I did the following:

mix.exs:

  • Added Guardian.
...
def application do
  [mod: {MyApp, []},
   applications: [:phoenix, ..., :guardian, ...]]
end

...

defp deps do
  [{:phoenix, "~> 1.2.1"},
   ...,
   {:guardian, "~> 0.14"}]
end

…then ran mix deps.get

config.exs

  • set allowed_algos to HS256
  • set issuer to Auth0 domain
  • set verify_issuer to false. This may have been what solved it, although I did try changing this in my initial attempt.
  • set secret_key to Auth0 client secret
  • set up my own serializer - see next step.
...
config :guardian, Guardian,
  allowed_algos: ["HS256"], # optional
  verify_module: Guardian.JWT,  # optional
  issuer: <Auth0 domain>,
  ttl: { 30, :days },
  allowed_drift: 2000,
  verify_issuer: false,
  secret_key: <Auth0 client secret>,
  serializer: MyApp.GuardianSerializer

...

serializer.ex

  • I’m not getting anything in/out of the token at this point, so this is not of any significance, just yet
defmodule MyApp.GuardianSerializer do
  @behaviour Guardian.Serializer

  def for_token(id), do: {:ok, id}
  def from_token(id), do: {:ok, id}

end

router.ex

  • Added the following Guardian plugs to the exisiting :api pipeline, as follows
...
pipeline :api do
  plug :accepts, ["json"]
  plug Guardian.Plug.VerifyHeader, realm: "Bearer"
  plug Guardian.Plug.EnsureAuthenticated
  plug Guardian.Plug.LoadResource
end
...

And that seemed to do the trick.

Thanks all, for your help

7 Likes

Late to the party, but I use the same scenario, and I just managed to make it work after a bit of pain.

I had to:

  1. Set allowed_algos to [“RS256”]
    https://community.auth0.com/questions/5476/authorization-api-signs-jwts-as-rs256-when-hs256-i
  2. Set the issuer to exactly what the JWT says (i.e. including the leading “https://” and the trailing “/”). Check the “iss” field of your token on https://jwt.io/
  3. Use the public key (found under Auth0 -> -> Settings -> Advanced Settings -> Certificates -> Signing Certificate), passed through JOSE.JWK.from_pem/1 as Guardian’s secret_key

Note that, as mentioned in https://github.com/ueberauth/guardian/issues/291, you can’t call JOSE.JWK.from_pem/1 from config.exs, so I had to move that call into the application start/2 function:

# (in config.exs)
...
config :guardian, Guardian,
  ...
  secret_key_pem: "-----BEGIN CERTIFICATE-----..."
  ...

# (in <app>/lib/<app-name>.ex)
def start(_type, _args) do
  guardian_env = Application.get_env(:guardian, Guardian)
  secret_key = guardian_env |> Keyword.get(:secret_key_pem) |> JOSE.JWK.from_pem
  new_guardian_env = guardian_env |> Keyword.put(:secret_key, secret_key)
  Application.put_env(:guardian, Guardian, new_guardian_env)

Hope this helps

1 Like

This blog details how the OP performed the same JWT Verification of Auth0 access token. Code also provided.

https://madebymany.com/stories/how-we-built-passwordless-authentication-with-auth0-and-elixir-phoenix

1 Like