Skip to content

Commit

Permalink
api: return 401 when auth header is missing or invalid.
Browse files Browse the repository at this point in the history
  • Loading branch information
thruflo committed Nov 14, 2024
1 parent 90d938e commit 72a9447
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 9 deletions.
2 changes: 1 addition & 1 deletion examples/gatekeeper-auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ First let's make a `GET` request to the proxy endpoint *without* the auth token.
```console
$ curl -sv "http://localhost:4000/proxy/v1/shape?table=items&offset=-1"
...
< HTTP/1.1 403 Forbidden
< HTTP/1.1 401 Unauthorized
...
```

Expand Down
21 changes: 19 additions & 2 deletions examples/gatekeeper-auth/api/lib/api/token.ex
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,26 @@ defmodule Api.Token do
end

def verify(%ShapeDefinition{} = request_shape, token) do
with {:ok, %{"shape" => token_params}} <- JWT.verify_and_validate(token, JWT.signer()),
{:ok, token_shape} <- Shape.from(token_params) do
with {:ok, shape_claim} <- validate(token) do
matches(request_shape, shape_claim)
end
end

defp validate(token) do
with {:ok, %{"shape" => shape_claim}} <- JWT.verify_and_validate(token, JWT.signer()) do
{:ok, shape_claim}
else
_alt ->
{:error, :invalid}
end
end

defp matches(%ShapeDefinition{} = request_shape, %{} = shape_claim) do
with {:ok, token_shape} <- Shape.from(shape_claim) do
Shape.matches(request_shape, token_shape)
else
_alt ->
false
end
end
end
7 changes: 5 additions & 2 deletions examples/gatekeeper-auth/api/lib/api_web/authenticator.ex
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@ defmodule ApiWeb.Authenticator do
request
end

def authorise(shape, request_header_list) do
header_map = Enum.into(request_header_list, %{})
def authorise(shape, request_headers) do
header_map = Enum.into(request_headers, %{})
header_key = String.downcase(@header_name)

with {:ok, "Bearer " <> token} <- Map.fetch(header_map, header_key) do
Token.verify(shape, token)
else
_alt ->
{:error, :missing}
end
end

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,18 @@ defmodule ApiWeb.Plugs.Auth.VerifyToken do

def call(%{assigns: %{shape: shape}, req_headers: headers} = conn, _opts) do
case Authenticator.authorise(shape, headers) do
true ->
{:error, message} when message in [:invalid, :missing] ->
conn
|> send_resp(401, "Unauthorized")
|> halt()

_alt ->
false ->
conn
|> send_resp(403, "Forbidden")
|> halt()

true ->
conn
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ defmodule ApiWeb.ProxyControllerTest do
test "requires auth", %{conn: conn} do
assert conn
|> get("/proxy/v1/shape", table: "items")
|> response(403)
|> response(401)
end

test "requires valid auth header", %{conn: conn} do
assert conn
|> put_req_header("authorization", "Bearer invalid-token")
|> get("/proxy/v1/shape", table: "items")
|> response(403)
|> response(401)
end

test "requires matching shape definition", %{conn: conn} do
Expand Down

0 comments on commit 72a9447

Please sign in to comment.