API token is invalid_token when decoding with guardian

My API which authenticates via auth0 and returns the access_token. During the callback, the access_token throws invalid_token error. Not sure what is going on.

Here are my codes.

router.ex

scope "/auth", PxrfWeb do
    pipe_through [:browser]

    get "/:provider", AuthController, :request
    get "/:provider/callback", AuthController, :callback
  end

config.exs

config :pxrf, Pxrf.Auth.Guardian,
  issuer: "https://myissuer.xx.auth0.com/",
  secret_key: "xxxxxxxx"

auth_controller.ex

...
def callback(%{assigns: %{ueberauth_auth: auth}} = conn, %{"state" => state} = _params) do
    IO.inspect(auth)

   token = auth.extra.raw_info.token.access_token
    
    case Pxrf.Auth.Guardian.decode_and_verify(token) do
      {:ok, claims} ->
        user = Accounts.get_user_by_username(claims["sub"])
        
      {:error, _reason} ->
        nil
    end
end
...

When I run the following

iex> Guardian.decode_and_verify("eyJasds-----access-token-")
{:error, :invalid_token}

Been breaking my head for the past couple of days and can’t figure it out what is wrong. Looks like all my configuration and setup in the auth0 application seems to be correct. But still no luck.

Tried 2 methods

Method 1

  1. Login via frontend to auth0
  2. Read the token and pass it to api
  3. Backend API is to validate the token

Method 2

  1. Send the request from api to auth0
  2. Callback should validate the return struct
  3. There the token shows invalid_token when decoding it.

Not sure which method is correct?

Are you using this Auth0 Ueberauth strategy?

If so, take a look at the callback functions in auth_controller.ex from the ueberauth example repo:

  def callback(%{assigns: %{ueberauth_failure: _fails}} = conn, _params) do
    conn
    |> put_flash(:error, "Failed to authenticate.")
    |> redirect(to: "/")
  end


  def callback(%{assigns: %{ueberauth_auth: auth}} = conn, _params) do
    case UserFromAuth.find_or_create(auth) do
      {:ok, user} ->
        conn
        |> put_flash(:info, "Successfully authenticated.")
        |> put_session(:current_user, user)
        |> configure_session(renew: true)
        |> redirect(to: "/")


      {:error, reason} ->
        conn
        |> put_flash(:error, reason)
        |> redirect(to: "/")
    end
  end

Yes I am using ueberauth_auth0 Strategy.

config.exs

config :ueberauth, Ueberauth,
  providers: [
    auth0: {Ueberauth.Strategy.Auth0, []}
  ]
config :ueberauth, Ueberauth.Strategy.Paypal.OAuth,
  domain: "my-domain.xx.auth0.com",
  client_id: "my+client+id",
  client_secret: "my+secret+key",

I wanted to use the Method 1 I’ve mentioned above whereby a user login with their auth0 credentials and which in return sends back the access_token. So I wanted to pass that token to my protected api. When I do that I get invalid_token error.

I have the follow pipeline and I think the error is thrown from there.

defmodule Pxrf.Auth.Pipeline do
  use Guardian.Plug.Pipeline,
    otp_app: :pxrf,
    module: Pxrf.Auth.Guardian,
    error_handler: Pxrf.Auth.GuardianErrorHandler

  
  plug Guardian.Plug.VerifySession, claims: %{"typ" => "access"}
  plug Guardian.Plug.VerifyHeader, scheme: "Bearer"
  plug Guardian.Plug.EnsureAuthenticated
  plug Guardian.Plug.LoadResource, allow_blank: true
end

Still no luck decoding and verifying the token with the following

Pxrf.Auth.Guardian.decode_and_verify(access_token)
{:error, :invalid_token}

Also tried Method 2 and with the access_token still can’t decode and verify. Am I missing something?

Btw “secret_key” and “client_secret” of Guardian and auth0 strategy is same.

If you peek inside the plug Guardian.Plug.VerifyHeader, you can see that it already handles decoding and verifying the header on line 92.

So the invalid token error is likely from attempting to decode and verify a token that’s already been decoded and verified. If you take another look at the example in my previous post, it shows how the two callback function heads check for authentication success or failure in the conn.

Is that means when I pass the token it is already validated and the current_resource is set into the connection? But I’m sending a valid token which I retrieved from auth0 login. If it is validated inside VerifyHeader then it is still throwing invalid_token error. What am I doing wrong?

Let’s say if I comment out the VerifyHeader and it throws unauthenticated error.

defmodule Pxrf.Auth.Pipeline do
  use Guardian.Plug.Pipeline,
    otp_app: :pxrf,
    module: Pxrf.Auth.Guardian,
    error_handler: Pxrf.Auth.GuardianErrorHandler

  plug Guardian.Plug.VerifySession
  # plug Guardian.Plug.VerifyHeader, scheme: "Bearer", claims: %{"typ" => "access"}
  plug Guardian.Plug.EnsureAuthenticated
  plug Guardian.Plug.LoadResource, allow_blank: true
end

Error:

{
    "error": "unauthenticated"
}

I checked with jwt.io for the validity of the token and it is valid though. Still breaking my head. Sorry for being noob.

The token is already validated when it reaches the callback function in auth_controller.ex so you shouldn’t be calling decode_and_verify again in the controller.

The presence of the ueberauth_failure key within conn.assigns indicates that it unsuccessfully ran through the Guardian pipeline whereas the presence of ueberauth_auth indicates that it successfully ran through the Guardian pipeline, including verifying the sesson and header, ensuring authentication, and loading resource.

If you want to access claims["sub"], I suggest you IO.inspect(conn) and it should already be there.

So since you’re using this ueberauth_auth0 strategy, you should be able to do something like conn.private.auth0_user["sub"].

If you comment out the VerifyHeader plug, it would make sense that a subsequent plug in the pipeline e.g. EnsureAuthenticated might fail with an unauthenticated error.

Hey,
First of all thanks for the help. I found the problem with the Guardian algo. The current version of the algo is HS512 by default. However my token isn’t. I had to add the following algo to the config file. It partially work with VerifyHeader in the pipeline.

config.exs

config :pxrf, Pxrf.Auth.Guardian,
  allowed_algos: ["HS256"], #Added this ALGO line 
  issuer: "https://myissuer.xx.auth0.com/",
  secret_key: "xxxxxxxx"

However now I get another new problem.

pipeline.ex

Doesn’t work with claims param

plug Guardian.Plug.VerifyHeader, scheme: "Bearer", claims: %{"typ" => "access"}

Works without the claims param

plug Guardian.Plug.VerifyHeader, scheme: "Bearer"

Is it safer to do this?

But why with claims params I still get invalid_token error?

If it doesn’t work when specifying the claims param but works without, that suggests the "typ" key in the decoded :claims map is not actually set to "access". Have you checked via IO.inspect to see if it’s something else? Could you share what the decoded JWT and/or conn looks like?

For example, if the decoded claims response looks like this example from the Use Access Token | Auth0 docs, then "typ" might be something like "JWT".

{
      "alg": "RS256",
      "typ": "JWT"
    }
    .
    {
      "iss": "https://example.auth0.com/",
      "aud": "https://api.example.com/calendar/v1/",
      "sub": "usr_123",
      "scope": "read write",
      "iat": 1458785796,
      "exp": 1458872196
    }

Yea… I get "typ":"JWT" so can I change the claim to JWT instead of access?

Decoded JWT

{
  "alg": "HS256",
  "typ": "JWT"
}
{
  "iss": "https://myissuer.xx.auth0.com/",
  "sub": "my_user_id",
  "iat": 1678777790,
  "exp": 1678864190
}

Yup, what you pass into claims option gets checked against the decoded token.

* `claims` - The literal claims to check to ensure that a token is valid
           ...
           claims_to_check <- Keyword.get(opts, :claims, %{}),
           ...
           {:ok, claims} <- Guardian.decode_and_verify(module, token, claims_to_check, opts) do

https://github.com/ueberauth/guardian/blob/master/lib/guardian/plug/verify_header.ex

source: guardian/verify_header.ex at master · ueberauth/guardian · GitHub

Try this:
plug Guardian.Plug.VerifyHeader, scheme: "Bearer", claims: %{"typ" => "JWT"}

Hi… sorry for late reply…
I just happen to try with the following and it still throws invalid_token

 plug Guardian.Plug.VerifyHeader, scheme: "Bearer", claims: %{"typ" => "JWT"}

Should I just remove the claims altogether? Without claims it works fine. Or is this security issue?