Closed nathanchere closed 5 years ago
OAuth2.Error at GET /signin/gitlab/callback
Server responded with status: 401
Headers:
server: nginx
date: Tue, 23 Oct 2018 13:12:56 GMT
content-type: application/json; charset=utf-8
content-length: 162
cache-control: no-store
pragma: no-cache
www-authenticate: Bearer realm="Doorkeeper", error="invalid_request", error_description="The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed."
x-content-type-options: nosniff
x-frame-options: SAMEORIGIN
x-request-id: 6c723674-d6df-41d2-a738-b71deb02f7a1
x-runtime: 0.019778
x-xss-protection: 1; mode=block
content-security-policy: object-src 'none'; worker-src https://assets.gitlab-static.net https://gl-canary.global.ssl.fastly.net https://gitlab.com blob:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://assets.gitlab-static.net https://gl-canary.global.ssl.fastly.net https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ https://apis.google.com; style-src 'self' 'unsafe-inline' https://assets.gitlab-static.net https://gl-canary.global.ssl.fastly.net; img-src * data: blob:; frame-src 'self' https://www.google.com/recaptcha/ https://content.googleapis.com https://content-compute.googleapis.com https://content-cloudbilling.googleapis.com https://content-cloudresourcemanager.googleapis.com https://*.codesandbox.io; frame-ancestors 'self'; connect-src 'self' https://assets.gitlab-static.net https://gl-canary.global.ssl.fastly.net wss://gitlab.com https://sentry.gitlab.net https://customers.gitlab.com https://snowplow.trx.gitlab.net
Body:
%{"error" => "invalid_request", "error_description" => "The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed."}
Call stack:
oauth2 lib/oauth2/client.ex:250 OAuth2.Client.get_token!/4
ueberauth_gitlab_strategy lib/ueberauth/strategy/gitlab/oauth.ex:66 Ueberauth.Strategy.Gitlab.OAuth.get_token!/2
ueberauth_gitlab_strategy lib/ueberauth/strategy/gitlab.ex:113 Ueberauth.Strategy.Gitlab.handle_callback!/1
ueberauth lib/ueberauth/strategy.ex:301 Ueberauth.Strategy.run_callback/2
lib/ninja_portal_web/controllers/auth_controller.ex:1 NinjaPortalWeb.AuthController.phoenix_controller_pipeline/1
As far as how I'm configuring it:
config :ueberauth, Ueberauth,
providers: [
gitlab: {Ueberauth.Strategy.Gitlab, [uid_field: :username, default_scope: "read_user"]},
...
Looks like some missing documentation possibly. I updated the README
with a known working configuration. Please try that out and let me know if that fixes your issue. The update is basically this:
config :ueberauth, Ueberauth,
providers: [
identity: { Ueberauth.Strategy.Identity, [
callback_methods: ["POST"],
uid_field: :email,
nickname_field: :username,
] },
gitlab: {Ueberauth.Strategy.Gitlab, [default_scope: "read_user"]},
]
The only difference there to what I have in my gitlab
provider settings is not including the uid_field: :username
pair, and it doesn't make a difference to the response from GitLab (i.e. The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed
)
Requests are generated in this format:
Looking at the Gitlab OAuth2 provider documentation, the format for the token based flow is pretty similar, e.g.:
https://gitlab.com/oauth/authorize?client_id=APP_ID&redirect_uri=REDIRECT_URI&response_type=token&state=YOUR_UNIQUE_STATE_HASH
and I change the outgoing response type to token
instead of code
, I at least get a valid redirect back. But that's pretty much the only thing I can change (other than adding a state
parameter) which doesn't break the request.
I'd like to be able to offer some help for you on this. Is there any way you can provide a sample app that reproduces this issue? I have been using a working configuration for some time now so I suspect something is different in your whole stack for versions of elixir, OTP, dependencies etc that could be exposing this.
Regarding changing the response type to token instead of code, that is curious because the RFC for web application flow, linked to from the Gitlab docs, explicitly states response type is required to be code.
Closing due to inactivity. Please let me know if you have any updates or issues.
I am experience the same exact issue:
[error] #PID<0.776.0> running TasksWeb.Endpoint (connection #PID<0.744.0>, stream id 8) terminated
Server: localhost:2000 (http)
Request: GET /auth/gitlab/callback?code=zzzzzzzzzzzzzzzzzz&state=myprivatestate
** (exit) an exception was raised:
** (OAuth2.Error) Server responded with status: 401
Headers:
date: Sat, 18 Apr 2020 11:56:39 GMT
content-type: application/json; charset=utf-8
content-length: 162
connection: keep-alive
set-cookie: __cfduid=yyyyyyyyyyyyyyyy; expires=Mon, 18-May-20 11:56:38 GMT; path=/; domain=.gitlab.com; HttpOnly; SameSite=Lax; Secure
cache-control: private, no-store
pragma: no-cache
www-authenticate: Bearer realm="Doorkeeper", error="invalid_request", error_description="The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed."
x-request-id: HLG2JJGfoma
x-runtime: 0.018386
gitlab-lb: fe-21-lb-gprd
gitlab-sv: web-33-sv-gprd
cf-cache-status: DYNAMIC
expect-ct: max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
server: cloudflare
cf-ray: 585e3425c9e1d224-MAN
cf-request-id: 022ebeeba00000d22491948200000001
Body:
"{\"error\":\"invalid_request\",\"error_description\":\"The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.\"}"
(oauth2) lib/oauth2/client.ex:298: OAuth2.Client.get_token!/4
(ueberauth_gitlab_strategy) lib/ueberauth/strategy/gitlab/oauth.ex:71: Ueberauth.Strategy.Gitlab.OAuth.get_token!/2
(ueberauth_gitlab_strategy) lib/ueberauth/strategy/gitlab.ex:116: Ueberauth.Strategy.Gitlab.handle_callback!/1
(ueberauth) lib/ueberauth/strategy.ex:307: Ueberauth.Strategy.run_callback/2
(tasks) TasksWeb.Router.auth/2
(tasks) lib/tasks_web/router.ex:1: TasksWeb.Router.__pipe_through0__/1
(phoenix) lib/phoenix/router.ex:283: Phoenix.Router.__call__/2
(tasks) lib/tasks_web/endpoint.ex:1: TasksWeb.Endpoint.plug_builder_call/2
(tasks) lib/plug/debugger.ex:132: TasksWeb.Endpoint."call (overridable 3)"/2
(tasks) lib/tasks_web/endpoint.ex:1: TasksWeb.Endpoint.call/2
(phoenix) lib/phoenix/endpoint/cowboy2_handler.ex:42: Phoenix.Endpoint.Cowboy2Handler.init/4
(cowboy) /home/developer/workspace/deps/cowboy/src/cowboy_handler.erl:41: :cowboy_handler.execute/2
(cowboy) /home/developer/workspace/deps/cowboy/src/cowboy_stream_h.erl:320: :cowboy_stream_h.execute/3
(cowboy) /home/developer/workspace/deps/cowboy/src/cowboy_stream_h.erl:302: :cowboy_stream_h.request_process/3
(stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/
My config:
# This file is responsible for configuring your application
# and its dependencies with the aid of the Mix.Config module.
#
# This configuration file is loaded before any dependency and
# is restricted to this project.
# General application configuration
use Mix.Config
config :tasks,
ecto_repos: [Tasks.Repo]
# Configures the endpoint
config :tasks, TasksWeb.Endpoint,
url: [host: "localhost"],
secret_key_base: "xxxxxxxxxxxxx",
render_errors: [view: TasksWeb.ErrorView, accepts: ~w(html json)],
pubsub: [name: Tasks.PubSub, adapter: Phoenix.PubSub.PG2],
live_view: [
signing_salt: "yyyyyyyyyyyyyyyyyyyyyyy"
]
config :ueberauth, Ueberauth,
providers: [
github: {Ueberauth.Strategy.Github, [default_scope: "user:email"]},
gitlab: {Ueberauth.Strategy.Gitlab, [default_scope: "read_user", api_version: "v4"]}
]
config :ueberauth, Ueberauth.Strategy.Github.OAuth,
client_id: System.get_env("GITHUB_CLIENT_ID"),
client_secret: System.get_env("GITHUB_CLIENT_SECRET")
config :ueberauth, Ueberauth.Strategy.Gitlab.OAuth,
client_id: System.get_env("GITLAB_CLIENT_ID"),
client_secret: System.get_env("GITLAB_CLIENT_SECRET")
# Configures Elixir's Logger
config :logger, :console,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]
# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason
config :mnesia,
dir: '.mnesia/#{Mix.env}/#{node()}'
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs"
My router:
defmodule TasksWeb.Router do
use TasksWeb, :router
require Logger
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
#plug :fetch_flash
plug :fetch_live_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
plug :assign_current_user
plug :put_root_layout, {TasksWeb.LayoutView, :root}
plug Plug.Validator, on_error: &TasksWeb.Router.validation_error_callback/2
end
pipeline :api do
plug :accepts, ["json"]
end
pipeline :require_login do
plug :check_user_is_logged
end
pipeline :auth do
plug Ueberauth,
otp_app: :tasks
end
scope "/auth", TasksWeb do
pipe_through [:browser, :auth]
get "/login", AuthController, :login
get "/:provider", AuthController, :request
get "/:provider/callback", AuthController, :callback
post "/:provider/callback", AuthController, :callback
post "/logout", AuthController, :logout
end
scope "/", TasksWeb do
pipe_through [:browser]
get "/", PageController, :index
end
scope "/", TasksWeb do
pipe_through [:browser, :require_login]
live "/todos", TodoLive
live "/todos/:date", TodoLive, private: %{validate: %{date: &Utils.Validators.Date.valid_iso8601?/1}}
end
def validation_error_callback(conn, errors) do
Logger.error "#{__MODULE__} failed to validate route #{conn.request_path} params: #{inspect(errors)}"
conn
|> put_status(:not_found)
|> put_view(TasksWeb.ErrorView)
|> render("404.html")
|> halt()
end
# Fetch the current user from the session and add it to `conn.assigns`. This
# will allow you to have access to the current user in your views with
# `@current_user`.
defp assign_current_user(conn, _) do
assign(conn, :current_user, get_session(conn, :current_user))
end
defp check_user_is_logged(conn, _) do
case get_session(conn, :current_user) do
nil ->
conn
|> put_flash(:info, "Please login to access this resource!")
|> redirect(to: "/auth/login")
|> halt()
_user ->
conn
end
end
# Other scopes may use custom stacks.
# scope "/api", TasksWeb do
# pipe_through :api
# end
end
My controller:
defmodule TasksWeb.AuthController do
@moduledoc """
Auth controller responsible for handling Ueberauth responses
"""
use TasksWeb, :controller
#plug Ueberauth
#alias Ueberauth.Strategy.Helpers
def login(conn, _params) do
render(conn, "login.html")
end
def logout(conn, _params) do
conn
|> put_flash(:info, "You have been logged out!")
|> clear_session()
|> redirect(to: "/")
end
def callback(%{assigns: %{ueberauth_failure: _fails} = fail} = conn, _params) do
IO.inspect fail, label: "FAILED AUTH"
conn
|> put_flash(:error, "Failed to authenticate.")
|> redirect(to: "/auth/login")
end
def callback(%{assigns: %{ueberauth_auth: auth}} = conn, _params) do
case Tasks.UserFromAuth.find_or_create(auth) do
{:ok, user} ->
conn
|> put_session(:current_user, user)
|> configure_session(renew: true)
|> redirect(to: "/")
{:error, reason} ->
conn
|> put_flash(:error, reason)
|> redirect(to: "/auth/login")
end
end
end
This works for the Github strategy, but doesn't work for the Gitlab strategy, and after digging into the code of your Library I was not able to figure out why, but I am also a newbie in Elixir.
It looks the request gets blocked by CloudFare due to the request not conforming exactly with the definition provided by Gitlab.
Do you have any insights why this may be happening?
The handover to GitLab works fine but on handling the callback throws this:
Looks like I'm not alone with it:
https://elixirforum.com/t/implementing-ueberauth-gitlab/15128
I'll look into it but leaving this here in case it's an already known and/or resolved issue.