README.md

# AuthPlugIntroduct

A secure Elixir Plug for authenticating requests using RSA public key cryptography. Clients sign requests with their private key; AuthPlugIntroduct verifies the signature using the stored public key.

## Installation

Add to your `mix.exs` deps:

```elixir
def deps do
  [
    {:auth_plug_introduct, "~> 0.1.0"}
  ]
end
```

## Configuration

In `config/config.exs`:

```elixir
config :auth_plug_introduct,
  key_header: "key_id",        # Header with user UUID
  sign_header: "sign",         # Header with Base64-encoded signature
  repo: YourApp.Repo,
  user_schema: YourApp.User
```

## User Schema

Your User schema must have:

```elixir
schema "users" do
  field :uuid, :binary_id, primary_key: true
  field :pub_key, :string      # RSA public key in PEM format
end
```

## Usage

Add to your Phoenix router:

```elixir
pipeline :api_auth do
  plug AuthPlugIntroduct.AuthUser
end

scope "/api", YourAppWeb do
  pipe_through :api_auth

  get "/profile", ProfileController, :show
  post "/items", ItemController, :create
end
```

Access the authenticated user:

```elixir
defmodule YourAppWeb.ProfileController do
  def show(conn, _params) do
    user = conn.assigns[:current_user]
    json(conn, %{uuid: user.uuid, email: user.email})
  end
end
```

## How It Works

1. Client includes headers: `key_id` (user UUID) and `sign` (Base64-encoded RSA signature)
2. AuthPlugIntroduct extracts headers and loads user from database
3. Verifies the signature against the request body using the user's public key
4. On success: user assigned to `conn.assigns[:current_user]`
5. On failure: returns 401 (missing/invalid headers) or 403 (signature invalid)

## Key Generation

Generate RSA key pair:

```bash
openssl genrsa -out private_key.pem 2048
openssl rsa -in private_key.pem -pubout -out public_key.pem
```

Store the public key in your database:

```elixir
public_key_pem = File.read!("public_key.pem")

YourApp.Repo.insert!(%YourApp.User{
  uuid: Ecto.UUID.generate(),
  email: "user@example.com",
  pub_key: public_key_pem,
  active: true
})
```

## Error Responses

**401 Unauthorized**
- Missing `key_id` or `sign` header
- User UUID not found in database
- Invalid Base64-encoded signature

**403 Forbidden**
- Signature verification failed
- Request body was modified after signing
- User's public key is invalid

## Security Notes

- Always use HTTPS/TLS for all requests
- Currently uses SHA-1; consider upgrading to SHA-256 for production
- Never commit private keys to version control
- Implement rate limiting to prevent brute force attacks
- Consider checking `user.active` field before granting access
- Request body is read entirely into memory; set appropriate size limits

## Troubleshooting

**401 errors**: Verify headers match configuration names, check user exists in database

**403 errors**: Ensure request body matches exactly what was signed, verify key pair is valid

**PEM format errors**: Ensure public key starts with `-----BEGIN PUBLIC KEY-----` and has no extra whitespace