README.md

# ReckonJwt

JWT authentication library for Reckon microservices ecosystem. Provides secure, stateless authentication across all Reckon services with a consistent, easy-to-use API.

## Features

- 🔐 **Secure JWT Generation** - Creates signed tokens with custom claims
- 🔄 **Token Refresh** - Automatic token refresh with extended session support
- 🛡️ **Phoenix Integration** - Drop-in middleware for Phoenix applications
- 🌐 **Cross-Service Auth** - Consistent authentication across microservices
- 📱 **Device Tracking** - Built-in device fingerprinting and session management
- ⚡ **High Performance** - Optimized for low-latency token operations

## Installation

Add `reckon_jwt` to your list of dependencies in `mix.exs`:

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

## Quick Start

### 1. Configuration

Add to your `config/config.exs`:

```elixir
config :reckon_jwt, ReckonJwt.Guardian,
  issuer: "reckon_identity",
  secret_key: "your-256-bit-secret-key",
  ttl: {4, :hours}
```

### 2. Generate Tokens

```elixir
# Generate session tokens (access + refresh)
{:ok, tokens} = ReckonJwt.generate_session_tokens(
  "account_123", 
  "session_456", 
  %{type: "web", fingerprint: "abc123"}
)

# tokens = %{
#   access_token: "eyJ0eXAi...",
#   refresh_token: "eyJ0eXAi...",
#   expires_at: 1640995200,
#   token_type: "Bearer",
#   account_id: "account_123",
#   session_id: "session_456"
# }
```

### 3. Validate Tokens

```elixir
{:ok, claims} = ReckonJwt.validate_token("eyJ0eXAi...")

# claims = %{
#   account_id: "account_123",
#   session_id: "session_456",
#   claims: %{"sub" => "account_123", ...},
#   token_type: "session",
#   expires_at: 1640995200
# }
```

### 4. Phoenix Integration

```elixir
# In your router.ex
pipeline :authenticated do
  plug ReckonJwt.Middleware
end

pipeline :admin do
  plug ReckonJwt.Middleware, required_scopes: ["admin"]
end

scope "/api", MyAppWeb do
  pipe_through [:api, :authenticated]
  
  get "/profile", ProfileController, :show
  get "/dashboard", DashboardController, :index
end
```

### 5. Use in Controllers

```elixir
defmodule MyAppWeb.ProfileController do
  use MyAppWeb, :controller

  def show(conn, _params) do
    account_id = ReckonJwt.Middleware.current_account_id(conn)
    claims = ReckonJwt.Middleware.jwt_claims(conn)
    
    # Use account_id to fetch user data
    render(conn, "profile.json", account_id: account_id)
  end
end
```

## API Reference

### Token Generation

#### `generate_session_tokens/3`
Generates both access and refresh tokens for user sessions.

```elixir
ReckonJwt.generate_session_tokens(account_id, session_id, device_info \\ %{})
```

#### `generate_access_token/2`
Generates a simple access token for service-to-service communication.

```elixir
ReckonJwt.generate_access_token(account_id, custom_claims \\ %{})
```

### Token Validation

#### `validate_token/1`
Validates any JWT token and extracts claims.

```elixir
ReckonJwt.validate_token(token)
```

#### `validate_session_token/1`
Validates session-specific tokens (requires session_id in claims).

```elixir
ReckonJwt.validate_session_token(token)
```

### Token Refresh

#### `refresh_session_tokens/1`
Refreshes access token using a valid refresh token.

```elixir
ReckonJwt.refresh_session_tokens(refresh_token)
```

### Middleware Options

```elixir
plug ReckonJwt.Middleware, [
  required_scopes: ["read", "write"],  # Required token scopes
  optional: false,                      # Make authentication optional
  token_key: "authorization",          # Header key for token
  account_key: :current_account_id,     # Conn assign key for account
  claims_key: :jwt_claims              # Conn assign key for claims
]
```

## Configuration Options

| Option | Description | Default |
|--------|-------------|----------|
| `:issuer` | Token issuer identifier | `"reckon_identity"` |
| `:secret_key` | JWT signing secret (required) | `nil` |
| `:ttl` | Access token lifetime | `{4, :hours}` |
| `:verify_issuer` | Verify token issuer | `true` |
| `:allowed_drift` | Clock drift tolerance (ms) | `2000` |

## Error Handling

The library provides detailed error responses:

```elixir
# Token validation errors
{:error, :token_expired}           # Token past expiration
{:error, :invalid_signature}       # Invalid token signature
{:error, :invalid_token_format}    # Malformed token
{:error, :invalid_session_token}   # Missing session information

# Refresh errors
{:error, :refresh_token_expired}   # Refresh token expired
{:error, :invalid_refresh_token}   # Invalid refresh token
```

## Security Features

### Token Claims
Tokens include comprehensive security claims:

```json
{
  "sub": "account_123",
  "iss": "reckon_identity",
  "aud": "reckon_services",
  "exp": 1640995200,
  "iat": 1640991600,
  "session_id": "session_456",
  "device_fingerprint": "abc123",
  "device_type": "web",
  "token_type": "session"
}
```

### Best Practices

1. **Secure Storage**: Store tokens securely on the client side
2. **HTTPS Only**: Always transmit tokens over encrypted connections
3. **Rotate Secrets**: Regularly rotate JWT signing keys
4. **Scope Validation**: Use minimal required scopes for each service
5. **Monitor Activity**: Track token usage and authentication patterns

## Multi-Service Setup

### Service A (Identity Service)
```elixir
# Generate tokens after authentication
{:ok, tokens} = ReckonJwt.generate_session_tokens(account_id, session_id)

# Return tokens to client
json(conn, %{data: tokens})
```

### Service B (Portal Service)
```elixir
# Validate tokens from other services
pipeline :authenticated do
  plug ReckonJwt.Middleware
end

# Use in controllers
def dashboard(conn, _params) do
  account_id = ReckonJwt.Middleware.current_account_id(conn)
  # ... use account_id for business logic
end
```

## Development

```bash
# Install dependencies
mix deps.get

# Run tests
mix test

# Generate documentation
mix docs

# Format code
mix format

# Type checking
mix dialyzer
```

## Contributing

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests
5. Run the test suite
6. Submit a pull request

## License

MIT License. See [LICENSE](LICENSE) for details.

## Support

For questions and support:

- 📖 [Documentation](https://hexdocs.pm/reckon_jwt)
- 🐛 [Issues](https://github.com/reckon-db-org/reckon_jwt/issues)
- 💬 [Discussions](https://github.com/reckon-db-org/reckon_jwt/discussions)