Crypto & Auth

Learn how to configure and use the authentication provider in R2R

Introduction

R2R’s CryptoProvider and AuthProvider combine to handle user authentication and cryptographic operations in your applications. This guide offers an in-depth look at the system’s architecture, configuration options, and best practices for implementation.

For a practical, step-by-step guide on implementing authentication in R2R, including code examples and common use cases, see our User Auth Cookbook.

When authentication is not required (require_authentication is set to false, which is the default in r2r.toml), unauthenticated requests will default to using the credentials of the default admin user.

This behavior ensures that operations can proceed smoothly in development or testing environments where authentication may not be enforced, but it should be used with caution in production settings.

Architecture Overview

R2R’s Crypto & Auth system is built on two primary components:

  1. Authentication Provider: Handles user registration, login, token management, and related operations.
  2. Cryptography Provider: Manages password hashing, verification, and generation of secure tokens.

These providers work in tandem to ensure secure user management and data protection.

Providers

Authentication Provider

The default R2RAuthProvider offers a complete authentication solution.

Key features:

  • JWT-based access and refresh tokens
  • User registration and login
  • Email verification (optional)
  • Password reset functionality
  • Superuser capabilities

Cryptography Provider

The default BCryptProvider handles cryptographic operations.

Key features:

  • Secure password hashing using bcrypt
  • Password verification
  • Generation of cryptographically secure verification codes

Configuration

Authentication Configuration

1[auth]
2provider = "r2r"
3access_token_minutes_lifetime = 60
4access_token_days_lifetime = 7
5require_authentication = true
6require_email_verification = false
7default_admin_email = "[email protected]"
8default_admin_password = "change_me_immediately"

Cryptography Configuration

1[crypto]
2provider = "bcrypt"
3salt_rounds = 12

Secret Key Management

R2R uses a secret key for JWT signing. Generate a secure key using:

$r2r generate-private-key

Set the key as an environment variable:

$export R2R_SECRET_KEY=your_generated_key

Never commit your secret key to version control. Use environment variables or secure key management solutions in production.

Auth Service Endpoints

The AuthProvider is responsible for providing functionality to support these core endpoints in R2R:

  1. register: User registration
  2. login: User authentication
  3. refresh_access_token: Token refresh
  4. logout: Session termination
  5. user: Retrieve user data
  6. change_password: Update user password
  7. request_password_reset: Initiate password reset
  8. confirm_password_reset: Complete password reset
  9. verify_email: Email verification
  10. get_user_profile: Fetch user profile
  11. update_user: Modify user profile
  12. delete_user_account: Account deletion

Implementation Guide

User Registration

1from r2r import R2RClient, UserCreate
2
3client = R2RClient("http://localhost:7272")
4
5result = client.register([email protected], secure_password123)
6print(f"Registration Result: {result}")

User Authentication

1login_result = client.login("[email protected]", "secure_password123")
2client.access_token = login_result['results']['access_token']['token']
3client.refresh_token = login_result['results']['refresh_token']['token']

Making Authenticated Requests

1user = client.user()
2print(f"Authenticated User Info: {user}")

Token Refresh

1refresh_result = client.refresh_access_token()
2client.access_token = refresh_result['results']['access_token']['token']

Logout

1logout_result = client.logout()
2print(f"Logout Result: {logout_result}")

Security Best Practices

  1. HTTPS: Always use HTTPS in production.
  2. Authentication Requirement: Set require_authentication to true in production.
  3. Email Verification: Enable require_email_verification for enhanced security.
  4. Password Policy: Implement and enforce strong password policies.
  5. Rate Limiting: Implement rate limiting on authentication endpoints.
  6. Token Management: Implement secure token storage and transmission.
  7. Regular Audits: Conduct regular security audits of your authentication system.

Custom Authentication Flows and External Identity Providers in R2R

Custom Authentication Flows

To implement custom authentication flows in R2R, you can extend the AuthProvider abstract base class. This allows you to create tailored authentication methods while maintaining compatibility with the R2R ecosystem.

Here’s an example of how to create a custom authentication provider:

1from r2r.base import AuthProvider, AuthConfig
2from r2r.abstractions.user import User, UserCreate, Token, TokenData
3from typing import Dict
4
5class CustomAuthProvider(AuthProvider):
6 def __init__(self, config: AuthConfig):
7 super().__init__(config)
8 # Initialize any custom attributes or connections here
9
10 def create_access_token(self, data: dict) -> str:
11 # Implement custom access token creation logic
12 pass
13
14 def create_refresh_token(self, data: dict) -> str:
15 # Implement custom refresh token creation logic
16 pass
17
18 def decode_token(self, token: str) -> TokenData:
19 # Implement custom token decoding logic
20 pass
21
22 def user(self, token: str) -> User:
23 # Implement custom user info retrieval logic
24 pass
25
26 def get_current_active_user(self, current_user: User) -> User:
27 # Implement custom active user validation logic
28 pass
29
30 def register(self, user: UserCreate) -> Dict[str, str]:
31 # Implement custom user registration logic
32 pass
33
34 def verify_email(self, verification_code: str) -> Dict[str, str]:
35 # Implement custom email verification logic
36 pass
37
38 def login(self, email: str, password: str) -> Dict[str, Token]:
39 # Implement custom login logic
40 pass
41
42 def refresh_access_token(self, user_email: str, refresh_access_token: str) -> Dict[str, str]:
43 # Implement custom token refresh logic
44 pass
45
46 async def auth_wrapper(self, auth: Optional[HTTPAuthorizationCredentials] = Security(security)) -> User:
47 # You can override this method if you need custom authentication wrapper logic
48 return await super().auth_wrapper(auth)
49
50 # Add any additional custom methods as needed
51 async def custom_auth_method(self, ...):
52 # Implement custom authentication logic
53 pass

Integrating External Identity Providers

To integrate external identity providers (e.g., OAuth, SAML) with R2R, you can create a custom AuthProvider that interfaces with these external services. Here’s an outline of how you might approach this:

  1. Create a new class that extends AuthProvider:
1from r2r.base import AuthProvider, AuthConfig
2from r2r.abstractions.user import User, UserCreate, Token, TokenData
3import some_oauth_library # Replace with actual OAuth library
4
5class OAuthAuthProvider(AuthProvider):
6 def __init__(self, config: AuthConfig):
7 super().__init__(config)
8 self.oauth_client = some_oauth_library.Client(
9 client_id=config.oauth_client_id,
10 client_secret=config.oauth_client_secret
11 )
12
13 async def login(self, email: str, password: str) -> Dict[str, Token]:
14 # Instead of password-based login, initiate OAuth flow
15 auth_url = self.oauth_client.get_authorization_url()
16 # Return auth_url or handle redirect as appropriate for your app
17 pass
18
19 async def oauth_callback(self, code: str) -> Dict[str, Token]:
20 # Handle OAuth callback
21 token = await self.oauth_client.get_access_token(code)
22 user_data = await self.oauth_client.get_user_info(token)
23
24 # Map external user data to R2R's user model
25 r2r_user = self._map_oauth_user_to_r2r_user(user_data)
26
27 # Create and return R2R tokens
28 access_token = self.create_access_token({"sub": r2r_user.email})
29 refresh_token = self.create_refresh_token({"sub": r2r_user.email})
30 return {
31 "access_token": Token(token=access_token, token_type="access"),
32 "refresh_token": Token(token=refresh_token, token_type="refresh"),
33 }
34
35 def _map_oauth_user_to_r2r_user(self, oauth_user_data: dict) -> User:
36 # Map OAuth user data to R2R User model
37 return User(
38 email=oauth_user_data["email"],
39 # ... map other fields as needed
40 )
41
42 # Implement other required methods...
  1. Update your R2R configuration to use the new provider:
1from r2r import R2R
2from r2r.base import AuthConfig
3from .custom_auth import OAuthAuthProvider
4
5auth_config = AuthConfig(
6 provider="custom_oauth",
7 oauth_client_id="your_client_id",
8 oauth_client_secret="your_client_secret",
9 # ... other config options
10)
11
12r2r = R2R(
13 auth_provider=OAuthAuthProvider(auth_config),
14 # ... other R2R configuration
15)
  1. Implement necessary routes in your application to handle OAuth flow:
1from fastapi import APIRouter, Depends
2from r2r import R2R
3
4router = APIRouter()
5
6@router.get("/login")
7async def login():
8 return await r2r.auth_provider.login(None, None) # Initiate OAuth flow
9
10@router.get("/oauth_callback")
11async def oauth_callback(code: str):
12 return await r2r.auth_provider.oauth_callback(code)

Remember to handle error cases, token storage, and user session management according to your application’s needs and the specifics of the external identity provider you’re integrating with.

This approach allows you to leverage R2R’s authentication abstractions while integrating with external identity providers, giving you flexibility in how you manage user authentication in your application.

Integrating External Identity Providers

To integrate with external identity providers (e.g., OAuth, SAML):

  1. Implement a custom AuthProvider.
  2. Handle token exchange and user profile retrieval.
  3. Map external user data to R2R’s user model.

Scaling Authentication

For high-traffic applications:

  1. Implement token caching (e.g., Redis).
  2. Consider microservices architecture for auth services.
  3. Use database replication for read-heavy operations.

Troubleshooting

Common issues and solutions:

  1. Token Expiration: Ensure proper token refresh logic.
  2. CORS Issues: Configure CORS settings for cross-origin requests.
  3. Password Reset Failures: Check email configuration and token expiration settings.

Performance Considerations

  1. BCrypt Rounds: Balance security and performance when setting salt_rounds.
  2. Database Indexing: Ensure proper indexing on frequently queried user fields.
  3. Caching: Implement caching for frequently accessed user data.

Conclusion

R2R’s Crypto & Auth system provides a solid foundation for building secure, scalable applications. By understanding its components, following best practices, and leveraging its flexibility, you can create robust authentication systems tailored to your specific needs.

For further customization and advanced use cases, refer to the R2R API Documentation and configuration guide.