+ {:error, changeset} ->
+ message =
+ Enum.map(changeset.errors, fn {field, {error, _}} ->
+ "#{field} #{error}"
+ end)
+ |> Enum.join("; ")
+
+ message =
+ String.replace(
+ message,
+ "ap_id has already been taken",
+ "nickname has already been taken"
+ )
+
+ conn
+ |> put_status(:forbidden)
+ |> put_flash(:error, "Error: #{message}.")
+ |> registration_details(params)
+
+ _ ->
+ {:register, :generic_error}
+ end
+ end
+
+ defp do_create_authorization(
+ conn,
+ %{
+ "authorization" =>
+ %{
+ "client_id" => client_id,
+ "redirect_uri" => redirect_uri
+ } = auth_attrs
+ },
+ user \\ nil
+ ) do
+ with {_, {:ok, %User{} = user}} <-
+ {:get_user, (user && {:ok, user}) || Authenticator.get_user(conn)},
+ %App{} = app <- Repo.get_by(App, client_id: client_id),
+ true <- redirect_uri in String.split(app.redirect_uris),
+ {:ok, scopes} <- validate_scopes(app, auth_attrs),
+ {:auth_active, true} <- {:auth_active, User.auth_active?(user)} do
+ Authorization.create_authorization(app, user, scopes)
+ end
+ end
+
+ defp get_app_from_request(conn, params) do
+ conn
+ |> fetch_client_credentials(params)
+ |> fetch_client
+ end
+
+ defp fetch_client({id, secret}) when is_binary(id) and is_binary(secret) do
+ Repo.get_by(App, client_id: id, client_secret: secret)
+ end
+
+ defp fetch_client({_id, _secret}), do: nil
+
+ defp fetch_client_credentials(conn, params) do
+ # Per RFC 6749, HTTP Basic is preferred to body params
+ with ["Basic " <> encoded] <- get_req_header(conn, "authorization"),
+ {:ok, decoded} <- Base.decode64(encoded),
+ [id, secret] <-
+ Enum.map(
+ String.split(decoded, ":"),
+ fn s -> URI.decode_www_form(s) end
+ ) do
+ {id, secret}
+ else
+ _ -> {params["client_id"], params["client_secret"]}