Using ueberauth and guardian to implement Auth, I get the token, but when I put the token in the header to access other routers, it still {"message": "invalid_token"}

When I visit http://localhost:4004/auth/sign_in The result is correct

{
	"data": {
		"id": 1,
		"token": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiIiLCJleHAiOjE2Njc0NjAzODcsImlhdCI6MTY2NzQ1ODU4NywiaXNzIjoiIiwianRpIjoiYjQ1Yzc2NWUtNTJkYS00MTIxLWEyNGUtN2VjNGYwODFhZDZmIiwibmJmIjoxNjY3NDU4NTg2LCJzdWIiOiIxIiwidHlwIjoiYWNjZXNzIn0.jPlcZjVo784A6_nPyZ8fJatO343TDxsvv-YFp9_Gs5dTSH3DjOqg12lQ24ciRi-JElG36__8I9ybBNazv7nnbA",
		"user_name": "gaofeng"
	}
}

And then I took the token to visit http://localhost:4004/user , the token is set in the header, and the result is incorrect
Header is

Result is

{

"message": "invalid_token"

}

This is the new content in my code
In config.exs.

config :ueberauth, Ueberauth,
  base_path: "/auth/sign_in",
  providers: [
    identity: {Ueberauth.Strategy.Identity, [
      callback_methods: ["POST", "GET"],
      nickname_field: :username,
      param_nesting: "user",
      uid_field: :username
    ]}
  ]

config :store_api, StoreApiWeb.Guardian,
        issure: "XXX",
        secret_key: "secret_key"
config :store_api, StoreApiWeb.Plug.AuthAccessPipeline,
  module: StoreApi.Auth,
  error_handler: StoreApiWeb.Plug.AuthErrorHandler

In auth module(auth.ex)

defmodule StoreApi.Auth do
  use Guardian, otp_app: :store_api

  def subject_for_token(%{id: id}, _claims) do
    {:ok, to_string(id)}
  end

  def subject_for_token(_, _) do
    IO.inspect "subject_for_token"
    {:error, :reason_for_error}
  end

  def resource_from_claims(%{"sub" => id}) do
    # Here we'll look up our resource from the claims, the subject can be
    # found in the `"sub"` key. In above `subject_for_token/2` we returned
    # the resource id so here we'll rely on that to look it up.
    resource = StoreApi.Accounts.get_user!(id)
    IO.inspect "resource_from_claims"
    IO.inspect resource
    {:ok,  resource}
  end

  def resource_from_claims(_claims) do
    IO.inspect "resource_from_claims=====_claims"
    {:error, :no_claims_sub}
  end
end

Auth Controller(authentication_controller.ex)

defmodule StoreApiWeb.AuthenticationController do
  use StoreApiWeb, :controller

  alias StoreApi.Accounts
  alias StoreApi.Accounts.User

  plug Ueberauth

  def identity_callback(conn, %{"user" => user_params}) do
    IO.inspect(user_params)
    user_name = user_params["user_name"]
    password = user_params["password"]
    handle_user_conn(Accounts.check_user(user_name, password), conn)
  end

  defp handle_user_conn(user, conn) do
    # IO.inspect(user)
    case user do
      {:ok, user} ->
        {:ok, jwt, _full_claims} =
          StoreApi.Auth.encode_and_sign(user, %{}, secret: "custom", ttl: {30, :minute})
        conn
        |> put_resp_header("authorization", "Bearer " <> jwt)
        |> json(%{data: %{token: jwt, user_name: user.user_name, id: user.id}})

      # Handle our own error to keep it generic
      {:error, msg} ->
        conn
        |> put_status(401)
        |> json(%{data: %{ status: false, msg: msg}})
    end
  end
end

In pulg
(auth_access_pipeline.ex)

defmodule StoreApiWeb.Plug.AuthAccessPipeline do
  use Guardian.Plug.Pipeline, otp_app: :store_api

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

auth_error_handler.ex

defmodule StoreApiWeb.Plug.AuthErrorHandler do
  import Plug.Conn
  import Phoenix.Controller, only: [json: 2]

  def auth_error(conn, {type, _reason}, _opts) do
    conn
    |> put_status(401)
    |> json(%{message: to_string(type)})
    |> halt()
  end
end

In my routers

defmodule StoreApiWeb.Router do
  use StoreApiWeb, :router

  pipeline :api do
    plug :accepts, ["json"]
  end

  scope "/api", StoreApiWeb do
    pipe_through :api
    resources "/user", UserController, except: [:new, :edit]
  end

  pipeline :browser do
    plug(:accepts, ["json"])
  end

  pipeline :authenticated do
    plug StoreApiWeb.Plug.AuthAccessPipeline
  end

  # 用户登录
  scope "/auth", StoreApiWeb do
    pipe_through :browser

    post "/sign_in", AuthenticationController, :identity_callback
  end

  @doc """
  用户信息相关API
  """
  scope "/user", StoreApiWeb do
    pipe_through :browser
    pipe_through :authenticated

    # 获取所有用户信息
    resources "/", UserController, except: [:new, :edit]
    post "/detail", UserController, :show
    #post "/delete", UserController, :delete
  end

  @doc """
  应用信息相关API
  """
  scope "/appinfo", StoreApiWeb do
    pipe_through :browser

    # 获取应用信息信息
    resources "/", AppinfoController, except: [:new, :edit]
    # 新增应用
    #post "/user_create", UserController, :user_create
  end

  # Enables LiveDashboard only for development
  #
  # If you want to use the LiveDashboard in production, you should put
  # it behind authentication and allow only admins to access it.
  # If your application does not have an admins-only section yet,
  # you can use Plug.BasicAuth to set up some basic authentication
  # as long as you are also using SSL (which you should anyway).
  if Mix.env() in [:dev, :test] do
    import Phoenix.LiveDashboard.Router

    scope "/" do
      pipe_through [:fetch_session, :protect_from_forgery]

      live_dashboard "/dashboard", metrics: StoreApiWeb.Telemetry
    end
  end

  # Enables the Swoosh mailbox preview in development.
  #
  # Note that preview only shows emails that were sent by the same
  # node running the Phoenix server.
  if Mix.env() == :dev do
    scope "/dev" do
      pipe_through [:fetch_session, :protect_from_forgery]

      forward "/mailbox", Plug.Swoosh.MailboxPreview
    end
  end
end

Thanks indeed!!!

I haven’t used Guardian, but the token should probably be sent as a “bearer token” in the Authorization header. So I suspect you have to set the Authorization header value to “Bearer eyJhbGciOiJIUzUxMiIsInR…”

1 Like

Thank you, I’ll try

when I set the Authorization header value to “Bearer eyJhbGciOiJIUzUxMiIsInR…”
returned the

{

"message": "invalid_token"

}

Thank you sincerely!

It is quite confusing when you update the original post to show progress in resolving your issue: people who previously looked at this thread may skip over it thinking they’ve already seen it, and for people new to the thread the earlier replies don’t match the original question anymore.

Anyway, it looks like now Guardian can find the token in the header. Hopefully someone with experience with Guardian can review your setup and identify any further issues that would explain why it does not accept your token. Does the plug not write a more detailed failure reason to the application’s logs?

Thank you for your suggestion. I have revised the title to make them look as consistent as possible,
Thank you also for helping me,Guardian can find the token in the header.

I haven’t used either of these so I may not be the best person to troubleshoot this but the message says the token itself is invalid and doesn’t suggest that it’s missing.

You could try putting the token into something like https://jwt-decoder.com/ or any number of other jwt decoders I found in a google search.

If I’m reading the line plug Guardian.Plug.VerifyHeader, realm: "Bearer", claims: %{"typ" => "access"} then the claim part should match that map. You can also try to inspect the module Guardian.Plug.VerifyHeader for what returns the “invalid_token” error message and maybe gain insight onto why that triggers here. My guess is it’s looking for something to be included in the token that perhaps isn’t there.

guardian/verify_header.ex at master · ueberauth/guardian · GitHub I believe shows that it should be trying to match the :claims option you’re passing in. If that claim isn’t included my guess is on line 92 Guardian.decode_and_verify(module, token, claims_to_check, opts) will trigger the error.

thanks very much !
I will try it!

Thanks everyone!
I found a solution.https://github.com/ueberauth/guardian/issues/559.
My config.exs is incorrect
Before

config :store_api, StoreApi.Guardian,
        issure: "store_api",
        secret_key: "xMIfc......"

After

config :store_api, StoreApi.Auth,
        issure: "store_api",
        secret_key: "xMIfc......"

auth.exs is my guardian module. But I made a mistake

Thank you all so much!!!!