Evrmore Authentication OAuth 2.0 Implementation Guide¶
Overview¶
This guide provides comprehensive documentation for the OAuth 2.0 implementation in Evrmore Authentication. It includes setup instructions, client registration, troubleshooting, and best practices based on real-world experience deploying the system.
Table of Contents¶
- Setup and Configuration
- Client Registration
- OAuth 2.0 Flow Implementation
- Troubleshooting
- Best Practices
- Example Applications
- API Reference
Setup and Configuration¶
Database Configuration¶
The OAuth system requires a properly configured database. By default, it uses SQLite located at ./evrmore_authentication/data/evrmore_auth.db.
- Set the database path in your
.envfile:
- Initialize the database:
This command creates the necessary tables for the OAuth system, including:
- oauth_clients - Stores registered OAuth client applications
- oauth_authorization_codes - Stores temporary authorization codes
- oauth_tokens - Stores access and refresh tokens
Running the Authentication Server¶
Start the authentication server with:
The server provides all the OAuth endpoints needed for the authorization flow.
Client Registration¶
Before using OAuth, you must register a client application. The system provides a dedicated script for this purpose.
Using the Client Registration Script¶
The scripts/register_oauth_client.py script simplifies OAuth client registration:
python3 scripts/register_oauth_client.py register \
--name "Your Application Name" \
--redirects "http://your-app.com/callback" \
--uri "http://your-app.com" \
--scopes "profile,email" \
--response-types "code"
Parameters:
- --name: Your application's name (displayed to users)
- --redirects: Comma-separated list of allowed redirect URIs
- --uri: Your application's main URI (optional)
- --scopes: Comma-separated list of scopes your app needs
- --response-types: Response types your app supports (usually "code")
Managing Clients¶
You can list registered clients:
Or delete a client:
Storing Client Credentials¶
The script will output client credentials that should be stored securely. For example:
Successfully registered new OAuth client:
ID: 92fae2b2-f231-43a4-945c-8c9f1f737627
Client ID: d5fdcc0c-7a88-4cfc-a1ff-6af04b92e9b0
Client Secret: XBBMQM9kppmbCyT5opG5FCZ0g89osYeKkrlNrmbIfKk
Name: FastAPI OAuth Example
Redirect URIs: http://localhost:8000/callback
Scopes: profile
Response Types: code
To update the OAuth client in your .env file or environment:
OAUTH_CLIENT_ID=d5fdcc0c-7a88-4cfc-a1ff-6af04b92e9b0
OAUTH_CLIENT_SECRET=XBBMQM9kppmbCyT5opG5FCZ0g89osYeKkrlNrmbIfKk
We recommend creating a dedicated .env.oauth file to store these credentials:
# OAuth Client Credentials
OAUTH_CLIENT_ID=d5fdcc0c-7a88-4cfc-a1ff-6af04b92e9b0
OAUTH_CLIENT_SECRET=XBBMQM9kppmbCyT5opG5FCZ0g89osYeKkrlNrmbIfKk
OAUTH_REDIRECT_URI=http://localhost:8000/callback
# Authorization Server Settings
AUTH_SERVER_URL=http://localhost:8001
OAuth 2.0 Flow Implementation¶
The OAuth 2.0 implementation follows the standard Authorization Code flow:
Step 1: Redirect to Authorization Endpoint¶
Redirect the user to the authorization endpoint:
import uuid
from urllib.parse import urlencode
# Generate state parameter to prevent CSRF
state = str(uuid.uuid4())
session['oauth_state'] = state
# Build the authorization URL
params = {
"client_id": CLIENT_ID,
"redirect_uri": REDIRECT_URI,
"response_type": "code",
"scope": "profile email",
"state": state
}
auth_url = f"{AUTH_SERVER}/oauth/authorize?{urlencode(params)}"
return redirect(auth_url)
Step 2: User Authentication¶
The user will be presented with an authentication page where they: 1. Enter their Evrmore wallet address 2. Receive a challenge to sign 3. Sign the challenge with their wallet 4. Submit the signature for verification
Step 3: Handle the Callback¶
When authentication succeeds, the user is redirected to your redirect URI with a code:
def oauth_callback(code, state):
# Verify state parameter
if state != session.get('oauth_state'):
return "Invalid state parameter", 400
# Exchange code for tokens
token_response = requests.post(
f"{AUTH_SERVER}/oauth/token",
data={
"grant_type": "authorization_code",
"code": code,
"redirect_uri": REDIRECT_URI,
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET
},
headers={
"Content-Type": "application/x-www-form-urlencoded"
}
)
token_data = token_response.json()
# Store tokens securely
session['access_token'] = token_data["access_token"]
session['refresh_token'] = token_data["refresh_token"]
return redirect('/profile')
Step 4: Access Protected Resources¶
Use the access token to fetch user info or access protected resources:
def get_user_profile():
access_token = session.get('access_token')
response = requests.get(
f"{AUTH_SERVER}/oauth/userinfo",
headers={
"Authorization": f"Bearer {access_token}"
}
)
user_data = response.json()
return render_template('profile.html', user=user_data)
Step 5: Refresh Tokens¶
When the access token expires, use the refresh token to get a new one:
def refresh_access_token():
refresh_token = session.get('refresh_token')
response = requests.post(
f"{AUTH_SERVER}/oauth/token",
data={
"grant_type": "refresh_token",
"refresh_token": refresh_token,
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET
},
headers={
"Content-Type": "application/x-www-form-urlencoded"
}
)
token_data = response.json()
# Update tokens
session['access_token'] = token_data["access_token"]
session['refresh_token'] = token_data["refresh_token"]
return token_data
Step 6: Logout (Token Revocation)¶
When the user logs out, revoke their tokens:
def logout():
access_token = session.get('access_token')
requests.post(
f"{AUTH_SERVER}/oauth/revoke",
json={
"token": access_token,
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET
}
)
# Clear session
session.clear()
return redirect('/')
Troubleshooting¶
Based on our experience, here are solutions to common OAuth implementation issues:
"Invalid client_id" Error¶
If you encounter an "Invalid client_id" error:
-
Verify that the client ID is registered in the database:
-
Ensure the database path is consistent between your server and client:
-
Re-register the client if necessary:
"Missing or expired OAuth session" Error¶
This error occurs when the OAuth session cookie is missing or invalid:
- Ensure cookies are properly stored and have appropriate security settings
- Check that the session duration is sufficient
- Verify the state parameter is properly managed
Authorization Code Exchange Fails (422 Error)¶
If token exchange fails with a 422 error:
-
Ensure the content type is correctly set for the token request:
-
Verify that you're sending form data rather than JSON:
-
Check that all required parameters are included:
grant_typecoderedirect_uriclient_idclient_secret
"Failed to verify signature" Error¶
If signature verification fails:
- Ensure the user is signing the exact challenge text provided
- Check that the signature and Evrmore address match
- Make sure you're using the correct verification order in any custom code
Debugging Tools¶
The repository includes two useful debugging tools:
-
monitor_logs.py - Real-time log monitoring:
-
check_auth_codes.py - Monitor OAuth authorization codes:
Best Practices¶
Security¶
- Use HTTPS in production environments
- Set secure cookie attributes:
httpOnly- Prevents JavaScript accesssecure- Ensures cookies are sent only over HTTPS-
sameSite=lax- Protects against CSRF -
Validate state parameter to prevent CSRF attacks
- Store client secrets securely and never expose them client-side
- Implement proper error handling for authentication failures
- Use refresh tokens for longer sessions rather than extending access token lifetimes
- Revoke tokens when users log out
Implementation¶
- Separate OAuth configuration into a dedicated file (like
.env.oauth) - Implement token refresh logic to handle expired tokens gracefully
- Add proper logging for debugging
- Handle errors gracefully with user-friendly messages
- Validate all inputs before sending requests
Example Applications¶
The repository includes example applications:
- fastapi_oauth_example.py - A complete FastAPI web application demonstrating the OAuth flow
Run the FastAPI example:
Then visit http://localhost:8000 in your browser.
API Reference¶
OAuth 2.0 Endpoints¶
- POST /oauth/clients - Register a new OAuth client
- GET/POST /oauth/authorize - Start the authorization process
- POST /oauth/token - Exchange authorization codes or refresh tokens
- GET /oauth/userinfo - Get the authenticated user's profile
- POST /oauth/revoke - Revoke tokens
- GET /auth - HTML authentication page for the OAuth flow
For detailed API documentation, see the FastAPI automatic docs at /docs when the server is running.
Support and Contact¶
If you encounter issues or have questions, please contact: - Email: dev@manticore.technology - GitHub: https://github.com/manticoretechnologies