ReckonJwt

View Source

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:

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

Quick Start

1. Configuration

Add to your config/config.exs:

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

2. Generate Tokens

# 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

{: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

# 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

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.

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

generate_access_token/2

Generates a simple access token for service-to-service communication.

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

Token Validation

validate_token/1

Validates any JWT token and extracts claims.

ReckonJwt.validate_token(token)

validate_session_token/1

Validates session-specific tokens (requires session_id in claims).

ReckonJwt.validate_session_token(token)

Token Refresh

refresh_session_tokens/1

Refreshes access token using a valid refresh token.

ReckonJwt.refresh_session_tokens(refresh_token)

Middleware Options

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

OptionDescriptionDefault
:issuerToken issuer identifier"reckon_identity"
:secret_keyJWT signing secret (required)nil
:ttlAccess token lifetime{4, :hours}
:verify_issuerVerify token issuertrue
:allowed_driftClock drift tolerance (ms)2000

Error Handling

The library provides detailed error responses:

# 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:

{
  "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)

# 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)

# 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

# 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 for details.

Support

For questions and support: