Skip to content

Commit f59a310

Browse files
committed
Added more context to authentication docs
1 parent b361a7f commit f59a310

File tree

7 files changed

+596
-3
lines changed

7 files changed

+596
-3
lines changed
Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
# API Key Authentication in Ellar
2+
3+
This guide demonstrates how to implement API Key authentication in Ellar using both header-based and query parameter-based approaches.
4+
5+
## Overview
6+
7+
API Key authentication is a simple yet effective way to secure your APIs. Ellar provides built-in support for three types of API Key authentication:
8+
9+
1. Header-based API Key
10+
2. Query Parameter-based API Key
11+
3. Cookie-based API Key
12+
13+
## Implementation Methods
14+
15+
### 1. Using Authentication Handler
16+
17+
```python
18+
# auth/api_key_scheme.py
19+
from ellar.auth import UserIdentity
20+
from ellar.auth.handlers import (
21+
HeaderAPIKeyAuthenticationHandler,
22+
QueryAPIKeyAuthenticationHandler,
23+
CookieAPIKeyAuthenticationHandler
24+
)
25+
from ellar.common import IHostContext
26+
from ellar.di import injectable
27+
28+
29+
@injectable
30+
class HeaderAPIKeyAuth(HeaderAPIKeyAuthenticationHandler):
31+
api_key = "your-secret-api-key" # In production, use secure storage
32+
api_key_name = "X-API-Key"
33+
34+
async def authentication_handler(
35+
self,
36+
context: IHostContext,
37+
api_key: str,
38+
) -> UserIdentity | None:
39+
if api_key == self.api_key:
40+
return UserIdentity(auth_type="api_key", api_key=api_key)
41+
return None
42+
43+
44+
@injectable
45+
class QueryAPIKeyAuth(QueryAPIKeyAuthenticationHandler):
46+
api_key = "your-secret-api-key"
47+
api_key_name = "api_key"
48+
49+
async def authentication_handler(
50+
self,
51+
context: IHostContext,
52+
api_key: str,
53+
) -> UserIdentity | None:
54+
if api_key == self.api_key:
55+
return UserIdentity(auth_type="api_key", api_key=api_key)
56+
return None
57+
```
58+
59+
Register the authentication handlers:
60+
61+
```python
62+
# server.py
63+
from ellar.app import AppFactory, use_authentication_schemes
64+
65+
application = AppFactory.create_from_app_module(
66+
lazyLoad('project_name.root_module:ApplicationModule'),
67+
config_module="project_name.config:DevelopmentConfig"
68+
)
69+
use_authentication_schemes([HeaderAPIKeyAuth, QueryAPIKeyAuth])
70+
```
71+
72+
### 2. Using Guard Strategy
73+
74+
```python
75+
# auth/guards.py
76+
from ellar.auth import UserIdentity
77+
from ellar.auth.guards import (
78+
GuardAPIKeyHeader,
79+
GuardAPIKeyQuery
80+
)
81+
from ellar.di import injectable
82+
83+
84+
@injectable
85+
class HeaderAPIKeyGuard(GuardAPIKeyHeader):
86+
api_key = "your-secret-api-key"
87+
api_key_name = "X-API-Key"
88+
89+
async def authentication_handler(
90+
self,
91+
context: IExecutionContext,
92+
api_key: str,
93+
) -> UserIdentity | None:
94+
if api_key == self.api_key:
95+
return UserIdentity(auth_type="api_key", api_key=api_key)
96+
self.raise_exception()
97+
98+
99+
@injectable
100+
class QueryAPIKeyGuard(GuardAPIKeyQuery):
101+
api_key = "your-secret-api-key"
102+
api_key_name = "api_key"
103+
104+
async def authentication_handler(
105+
self,
106+
context: IExecutionContext,
107+
api_key: str,
108+
) -> UserIdentity | None:
109+
if api_key == self.api_key:
110+
return UserIdentity(auth_type="api_key", api_key=api_key)
111+
self.raise_exception()
112+
```
113+
114+
## Controller Implementation
115+
116+
```python
117+
from ellar.common import Controller, get
118+
from ellar.auth import AuthenticationRequired
119+
120+
121+
@Controller('/api')
122+
@AuthenticationRequired(['HeaderAPIKeyAuth', 'QueryAPIKeyAuth'])
123+
class APIController:
124+
@get('/data')
125+
async def get_data(self):
126+
return {"message": "Protected data"}
127+
```
128+
129+
## Testing the Implementation
130+
131+
```bash
132+
# Using Header-based API Key
133+
curl http://localhost:8000/api/data \
134+
-H "X-API-Key: your-secret-api-key"
135+
136+
# Using Query Parameter-based API Key
137+
curl "http://localhost:8000/api/data?api_key=your-secret-api-key"
138+
```
139+
140+
## Security Best Practices
141+
142+
1. **API Key Storage**:
143+
- Never hardcode API keys in source code
144+
- Use environment variables or secure key management systems
145+
- Rotate API keys periodically
146+
147+
2. **Transport Security**:
148+
- Always use HTTPS in production
149+
- Consider implementing rate limiting
150+
- Log and monitor API key usage
151+
152+
3. **Key Management**:
153+
- Implement API key rotation
154+
- Maintain an audit trail of API key usage
155+
- Implement key revocation mechanisms
156+
157+
## Advanced Implementation
158+
159+
### API Key with Scopes
160+
161+
```python
162+
from typing import List
163+
from ellar.auth import UserIdentity
164+
from ellar.auth.handlers import HeaderAPIKeyAuthenticationHandler
165+
166+
167+
@injectable
168+
class ScopedAPIKeyAuth(HeaderAPIKeyAuthenticationHandler):
169+
api_keys = {
170+
"key1": ["read"],
171+
"key2": ["read", "write"],
172+
}
173+
api_key_name = "X-API-Key"
174+
175+
async def authentication_handler(
176+
self,
177+
context: IHostContext,
178+
api_key: str,
179+
) -> UserIdentity | None:
180+
if api_key in self.api_keys:
181+
return UserIdentity(
182+
auth_type="api_key",
183+
api_key=api_key,
184+
scopes=self.api_keys[api_key]
185+
)
186+
return None
187+
```
188+
189+
## Manual OpenAPI Integration
190+
191+
Ellar automatically generates OpenAPI documentation when you use and class in `ellar.auth.handlers` and `ellar.auth.guards`. But if you want to manually add it, you can do so by using the `OpenAPIDocumentBuilder` class.
192+
193+
```python
194+
from ellar.openapi import ApiTags, OpenAPIDocumentBuilder
195+
196+
@Controller
197+
@ApiTags(name='API', security=[{"ApiKeyAuth": []}])
198+
class APIController:
199+
pass
200+
201+
# In your OpenAPI configuration
202+
document_builder = OpenAPIDocumentBuilder()
203+
document_builder.add_security_scheme(
204+
"ApiKeyAuth",
205+
{
206+
"type": "apiKey",
207+
"in": "header",
208+
"name": "X-API-Key"
209+
}
210+
)
211+
```
212+
213+
## Custom Error Handling
214+
215+
```python
216+
from ellar.common import IExecutionContext
217+
from ellar.common.responses import JSONResponse
218+
from ellar.core.exceptions import as_exception_handler
219+
220+
221+
@as_exception_handler(401)
222+
def invalid_api_key_exception_handler(ctx: IExecutionContext, exc: Exception) -> JSONResponse:
223+
return JSONResponse(
224+
status_code=401,
225+
content={
226+
"message": "Invalid API key",
227+
"error": "unauthorized"
228+
}
229+
)
230+
```
231+
See [Custom Error Handling](../overview/exception_handling.md) for more information.
232+
233+
## Complete Examples
234+
235+
For a complete working example of API Key authentication, visit the [Ellar examples repository](https://github.com/python-ellar/ellar/tree/main/examples).

docs/security/authentication/auth-handler-strategy.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Just like AuthGuard, we need to create its equivalent. But first we need to crea
1212
of your application for us to define a `JWTAuthentication` handler.
1313

1414

15-
```python title='prject_name/auth_scheme.py' linenums='1'
15+
```python title='project_name/auth_scheme.py' linenums='1'
1616
import typing as t
1717
from ellar.common.serializer.guard import (
1818
HTTPAuthorizationCredentials,
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Authentication in Ellar
2+
3+
Authentication is an essential part of most applications. It verifies the identity of users interacting with your application. Ellar provides flexible and powerful authentication mechanisms to suit different application needs.
4+
5+
## Overview
6+
7+
Ellar offers two main approaches to authentication:
8+
9+
1. **Guard Strategy** - Authentication performed at the route handler level
10+
2. **Authentication Handler Strategy** - Authentication performed at the middleware layer
11+
12+
### When to Use Each Strategy
13+
14+
- **Guard Strategy**:
15+
- When you need fine-grained control over authentication at the route level
16+
- When authentication logic varies between different routes
17+
- When you want to combine multiple authentication methods
18+
19+
- **Authentication Handler Strategy**:
20+
- When you want consistent authentication across your application
21+
- When authentication should happen early in the request pipeline
22+
- When you need to integrate with existing authentication middleware
23+
24+
## Available Authentication Methods
25+
26+
Ellar supports various authentication methods out of the box:
27+
28+
- JWT Authentication
29+
- HTTP Basic Authentication
30+
- HTTP Bearer Authentication
31+
- API Key Authentication (Header, Query, Cookie)
32+
- Custom Authentication Schemes
33+
34+
## Getting Started
35+
36+
Choose the authentication strategy that best fits your needs:
37+
38+
- [Guard-based Authentication](./guard-strategy.md) - Learn how to implement authentication using Guards
39+
- [Authentication Handler Strategy](./auth-handler-strategy.md) - Implement authentication at the middleware level
40+
- [JWT Authentication Example](./jwt-authentication.md) - Complete example of JWT authentication
41+
- [API Key Authentication](./api-key-authentication.md) - Implement API key-based authentication
42+
43+
## Best Practices
44+
45+
1. **Security First**:
46+
- Never store passwords in plain text
47+
- Use secure token generation and validation
48+
- Implement proper error handling
49+
50+
2. **Performance**:
51+
- Choose the appropriate authentication layer
52+
- Implement caching where appropriate
53+
- Consider token expiration strategies
54+
55+
3. **User Experience**:
56+
- Implement proper token refresh mechanisms
57+
- Provide clear error messages
58+
- Consider rate limiting
59+
60+
4. **Code Organization**:
61+
- Separate authentication logic from business logic
62+
- Use dependency injection for services
63+
- Follow Ellar's module structure
64+
65+
## Next Steps
66+
67+
Start with the authentication strategy that best matches your requirements:
68+
69+
- For route-level authentication control, begin with [Guard Strategy](./guard-strategy.md)
70+
- For application-wide authentication, check out [Authentication Handler Strategy](./auth-handler-strategy.md)

0 commit comments

Comments
 (0)