0
# Utility Functions
1
2
Helper functions for URLs, tokens, validation, communication, and other common security operations that support Flask-Security's core functionality.
3
4
## Capabilities
5
6
### URL and Navigation Utilities
7
8
Functions for generating security-related URLs and handling navigation within Flask-Security.
9
10
```python { .api }
11
def url_for_security(endpoint, **values):
12
"""
13
Generate URLs for Flask-Security endpoints.
14
15
Parameters:
16
- endpoint: Security endpoint name (e.g., 'login', 'register', 'reset_password')
17
- values: Additional URL parameters and query arguments
18
19
Returns:
20
Generated URL string for the security endpoint
21
"""
22
23
def get_url(endpoint_or_url, qparams=None, **values):
24
"""
25
Generate URLs with query parameters.
26
27
Parameters:
28
- endpoint_or_url: Flask endpoint name or absolute URL
29
- qparams: Dictionary of query parameters to append
30
- values: Additional URL generation values
31
32
Returns:
33
Complete URL with query parameters
34
"""
35
36
def transform_url(url, qparams=None, **params):
37
"""
38
Transform URLs with custom logic and parameters.
39
40
Parameters:
41
- url: Base URL to transform
42
- qparams: Query parameters to add or modify
43
- params: Additional transformation parameters
44
45
Returns:
46
Transformed URL string
47
"""
48
49
def get_post_login_redirect():
50
"""
51
Get redirect URL after successful login.
52
53
Returns:
54
URL string for post-login redirect, considering 'next' parameter
55
"""
56
57
def get_logout_redirect():
58
"""
59
Get redirect URL after logout.
60
61
Returns:
62
URL string for post-logout redirect
63
"""
64
```
65
66
### Token and Security Utilities
67
68
Functions for generating, validating, and managing security tokens and cryptographic operations.
69
70
```python { .api }
71
def get_hmac(password):
72
"""
73
Generate HMAC for token security and password operations.
74
75
Parameters:
76
- password: Password or data to generate HMAC for
77
78
Returns:
79
HMAC digest string
80
"""
81
82
def check_and_get_token_status(token, serializer, max_age=None):
83
"""
84
Validate token status and return token information.
85
86
Parameters:
87
- token: Token string to validate
88
- serializer: Token serializer instance
89
- max_age: Maximum token age in seconds (optional)
90
91
Returns:
92
Tuple of (is_expired: bool, is_invalid: bool, token_data: dict)
93
"""
94
95
def generate_token(data, salt=None):
96
"""
97
Generate secure token from data.
98
99
Parameters:
100
- data: Data to encode in token
101
- salt: Salt for token generation (optional)
102
103
Returns:
104
Generated token string
105
"""
106
107
def verify_token(token, salt=None, max_age=None):
108
"""
109
Verify and decode token data.
110
111
Parameters:
112
- token: Token string to verify
113
- salt: Salt used for token generation (optional)
114
- max_age: Maximum acceptable token age in seconds
115
116
Returns:
117
Decoded token data if valid, None if invalid or expired
118
"""
119
```
120
121
### Password Validation Utilities
122
123
Functions for validating password strength, complexity, and security requirements.
124
125
```python { .api }
126
def password_length_validator(password, min_length=None, max_length=None):
127
"""
128
Validate password length requirements.
129
130
Parameters:
131
- password: Password string to validate
132
- min_length: Minimum required length (default: from config)
133
- max_length: Maximum allowed length (default: from config)
134
135
Returns:
136
True if valid, raises ValidationError if invalid
137
"""
138
139
def password_complexity_validator(password, **requirements):
140
"""
141
Validate password complexity requirements.
142
143
Parameters:
144
- password: Password string to validate
145
- requirements: Complexity requirements dict (uppercase, lowercase, digits, symbols)
146
147
Returns:
148
True if valid, raises ValidationError if invalid
149
"""
150
151
def password_breached_validator(password, check_breach_count=True):
152
"""
153
Check password against known breach databases.
154
155
Parameters:
156
- password: Password string to check
157
- check_breach_count: Whether to check breach count threshold
158
159
Returns:
160
True if password is safe, raises ValidationError if breached
161
"""
162
163
def pwned(password, user_agent=None, request_timeout=1.0):
164
"""
165
Check if password appears in HaveIBeenPwned breach database.
166
167
Parameters:
168
- password: Password string to check
169
- user_agent: Custom User-Agent for API requests
170
- request_timeout: Timeout for API request in seconds
171
172
Returns:
173
Number of times password appears in breaches, 0 if safe
174
"""
175
```
176
177
### Communication Utilities
178
179
Functions for sending emails, SMS messages, and other forms of communication.
180
181
```python { .api }
182
def send_mail(subject, recipient, template, **context):
183
"""
184
Send email utility function with template rendering.
185
186
Parameters:
187
- subject: Email subject line
188
- recipient: Recipient email address
189
- template: Template name for email body
190
- context: Template context variables
191
192
Returns:
193
True if email sent successfully, False otherwise
194
"""
195
196
class MailUtil:
197
"""
198
Email handling and template rendering utility class.
199
"""
200
201
def __init__(self, app=None):
202
"""
203
Initialize mail utility.
204
205
Parameters:
206
- app: Flask application instance (optional)
207
"""
208
209
def init_app(self, app):
210
"""
211
Initialize mail utility with Flask app.
212
213
Parameters:
214
- app: Flask application instance
215
"""
216
217
def send_mail(self, template, subject, recipient, sender=None, **kwargs):
218
"""
219
Send templated email.
220
221
Parameters:
222
- template: Email template name
223
- subject: Email subject
224
- recipient: Recipient email address
225
- sender: Sender email address (optional)
226
- kwargs: Template context variables
227
228
Returns:
229
True if sent successfully, False otherwise
230
"""
231
232
def render_template(self, template, **kwargs):
233
"""
234
Render email template with context.
235
236
Parameters:
237
- template: Template name to render
238
- kwargs: Template context variables
239
240
Returns:
241
Rendered template string
242
"""
243
244
class EmailValidateException(Exception):
245
"""Exception raised for email validation errors."""
246
pass
247
```
248
249
### SMS Communication Classes
250
251
Classes and factory for SMS message sending with multiple provider support.
252
253
```python { .api }
254
class SmsSenderBaseClass:
255
"""
256
Abstract base class for SMS senders.
257
"""
258
259
def __init__(self, **kwargs):
260
"""
261
Initialize SMS sender.
262
263
Parameters:
264
- kwargs: Provider-specific configuration
265
"""
266
267
def send_sms(self, from_number, to_number, msg):
268
"""
269
Send SMS message.
270
271
Parameters:
272
- from_number: Sender phone number
273
- to_number: Recipient phone number
274
- msg: Message content
275
276
Returns:
277
True if sent successfully, False otherwise
278
"""
279
280
class SmsSenderFactory:
281
"""
282
Factory for creating SMS sender instances.
283
"""
284
285
@staticmethod
286
def createSender(name, **kwargs):
287
"""
288
Create SMS sender instance by name.
289
290
Parameters:
291
- name: SMS service name ('Dummy', 'Twilio', etc.)
292
- kwargs: Service-specific configuration
293
294
Returns:
295
SMS sender instance
296
"""
297
298
class DummySmsSender(SmsSenderBaseClass):
299
"""
300
Dummy SMS sender implementation for testing and development.
301
"""
302
303
def send_sms(self, from_number, to_number, msg):
304
"""Send SMS (dummy implementation that logs message)."""
305
print(f"SMS to {to_number}: {msg}")
306
return True
307
```
308
309
### Time and Request Utilities
310
311
Utility functions for handling time operations and request context management.
312
313
```python { .api }
314
def naive_utcnow():
315
"""
316
Get current UTC time as naive datetime.
317
318
Returns:
319
Datetime object representing current UTC time without timezone info
320
"""
321
322
def get_request_attr(name):
323
"""
324
Get attribute from current request context.
325
326
Parameters:
327
- name: Attribute name to retrieve from request
328
329
Returns:
330
Attribute value if found, None otherwise
331
"""
332
333
def get_request_attr_or_default(name, default=None):
334
"""
335
Get request attribute with default fallback.
336
337
Parameters:
338
- name: Attribute name to retrieve
339
- default: Default value if attribute not found
340
341
Returns:
342
Attribute value or default
343
"""
344
```
345
346
### Specialized Utility Classes
347
348
Utility classes for managing specific Flask-Security features and operations.
349
350
```python { .api }
351
class PasswordUtil:
352
"""
353
Password management and policy utility class.
354
"""
355
356
def __init__(self, app=None):
357
"""Initialize password utility."""
358
359
def init_app(self, app):
360
"""Initialize with Flask app."""
361
362
def hash_password(self, password):
363
"""
364
Hash password using configured algorithm.
365
366
Parameters:
367
- password: Plain text password to hash
368
369
Returns:
370
Hashed password string
371
"""
372
373
def verify_password(self, password, password_hash):
374
"""
375
Verify password against hash.
376
377
Parameters:
378
- password: Plain text password
379
- password_hash: Stored password hash
380
381
Returns:
382
True if password matches, False otherwise
383
"""
384
385
def validate_password(self, password):
386
"""
387
Validate password against configured policies.
388
389
Parameters:
390
- password: Password to validate
391
392
Returns:
393
True if valid, raises ValidationError if invalid
394
"""
395
396
class PhoneUtil:
397
"""
398
Phone number validation and formatting utility class.
399
"""
400
401
def __init__(self, app=None):
402
"""Initialize phone utility."""
403
404
def init_app(self, app):
405
"""Initialize with Flask app."""
406
407
def validate_phone_number(self, phone_number):
408
"""
409
Validate phone number format.
410
411
Parameters:
412
- phone_number: Phone number string to validate
413
414
Returns:
415
True if valid, False otherwise
416
"""
417
418
def normalize_phone_number(self, phone_number):
419
"""
420
Normalize phone number to standard format.
421
422
Parameters:
423
- phone_number: Phone number to normalize
424
425
Returns:
426
Normalized phone number string
427
"""
428
429
class UsernameUtil:
430
"""
431
Username validation and management utility class.
432
"""
433
434
def __init__(self, app=None):
435
"""Initialize username utility."""
436
437
def init_app(self, app):
438
"""Initialize with Flask app."""
439
440
def validate_username(self, username):
441
"""
442
Validate username format and requirements.
443
444
Parameters:
445
- username: Username to validate
446
447
Returns:
448
True if valid, raises ValidationError if invalid
449
"""
450
451
def normalize_username(self, username):
452
"""
453
Normalize username format.
454
455
Parameters:
456
- username: Username to normalize
457
458
Returns:
459
Normalized username string
460
"""
461
```
462
463
### TOTP Utility Class
464
465
Time-based One-Time Password generation and validation for two-factor authentication.
466
467
```python { .api }
468
class Totp:
469
"""
470
Time-based One-Time Password generation and validation utility class.
471
"""
472
473
def __init__(self, secret=None, issuer=None):
474
"""
475
Initialize TOTP utility.
476
477
Parameters:
478
- secret: Base32-encoded secret key (optional, generates if not provided)
479
- issuer: Issuer name for TOTP (optional)
480
"""
481
482
def generate_password(self, counter=None):
483
"""
484
Generate TOTP password for current time window.
485
486
Parameters:
487
- counter: Time counter (optional, uses current time if not provided)
488
489
Returns:
490
6-digit TOTP code as string
491
"""
492
493
def verify(self, token, window=0):
494
"""
495
Verify TOTP token against current time.
496
497
Parameters:
498
- token: TOTP token string to verify
499
- window: Number of time windows to check (default: 0)
500
501
Returns:
502
True if token is valid, False otherwise
503
"""
504
505
def generate_qr_code(self, name, issuer=None):
506
"""
507
Generate QR code for TOTP secret.
508
509
Parameters:
510
- name: Account name for QR code
511
- issuer: Issuer name (optional)
512
513
Returns:
514
QR code image data as base64 string
515
"""
516
517
@property
518
def secret(self):
519
"""
520
Get TOTP secret key.
521
522
Returns:
523
Base32-encoded secret string
524
"""
525
526
@property
527
def provisioning_uri(self):
528
"""
529
Get provisioning URI for authenticator apps.
530
531
Returns:
532
otpauth:// URI string
533
"""
534
```
535
536
## Usage Examples
537
538
### URL Generation and Navigation
539
540
```python
541
from flask_security import url_for_security, get_url
542
543
@app.route('/custom-login')
544
def custom_login_redirect():
545
"""Redirect to Flask-Security login page."""
546
login_url = url_for_security('login', next='/dashboard')
547
return redirect(login_url)
548
549
@app.route('/user-profile')
550
@login_required
551
def user_profile():
552
"""Display user profile with navigation links."""
553
554
# Generate security URLs
555
change_password_url = url_for_security('change_password')
556
logout_url = url_for_security('logout')
557
558
# Add query parameters
559
reset_url = get_url('security.forgot_password',
560
qparams={'email': current_user.email})
561
562
return render_template('profile.html',
563
change_password_url=change_password_url,
564
logout_url=logout_url,
565
reset_url=reset_url)
566
```
567
568
### Token Generation and Validation
569
570
```python
571
from flask_security import generate_token, verify_token
572
573
@app.route('/send-invite', methods=['POST'])
574
@roles_required('admin')
575
def send_invite():
576
"""Send invitation token to new user."""
577
email = request.form.get('email')
578
579
# Generate invitation token
580
token_data = {'email': email, 'action': 'invite'}
581
token = generate_token(token_data, salt='invite-salt')
582
583
# Send invitation email
584
invite_url = url_for('accept_invite', token=token, _external=True)
585
send_mail(
586
subject='You are invited to join our platform',
587
recipient=email,
588
template='invite_email',
589
invite_url=invite_url
590
)
591
592
flash(f'Invitation sent to {email}')
593
return redirect(url_for('admin_users'))
594
595
@app.route('/accept-invite/<token>')
596
def accept_invite(token):
597
"""Accept invitation using token."""
598
599
# Verify token (valid for 7 days)
600
token_data = verify_token(token, salt='invite-salt', max_age=604800)
601
602
if not token_data:
603
flash('Invalid or expired invitation link')
604
return redirect(url_for('security.register'))
605
606
# Pre-fill registration form with invited email
607
return redirect(url_for('security.register', email=token_data['email']))
608
```
609
610
### Password Validation
611
612
```python
613
from flask_security import (
614
password_length_validator,
615
password_complexity_validator,
616
password_breached_validator
617
)
618
619
def validate_new_password(password):
620
"""Custom password validation with multiple checks."""
621
622
try:
623
# Check length requirements
624
password_length_validator(password, min_length=8, max_length=128)
625
626
# Check complexity requirements
627
password_complexity_validator(password, {
628
'uppercase': 1,
629
'lowercase': 1,
630
'digits': 1,
631
'symbols': 1
632
})
633
634
# Check against breach database
635
password_breached_validator(password)
636
637
return True
638
639
except ValidationError as e:
640
return False, str(e)
641
642
@app.route('/validate-password', methods=['POST'])
643
def validate_password_endpoint():
644
"""API endpoint for password validation."""
645
password = request.json.get('password')
646
647
is_valid, error_message = validate_new_password(password)
648
649
return jsonify({
650
'valid': is_valid,
651
'error': error_message if not is_valid else None
652
})
653
```
654
655
### Email Communication
656
657
```python
658
from flask_security import send_mail, MailUtil
659
660
# Initialize mail utility
661
mail_util = MailUtil(app)
662
663
@app.route('/send-welcome-email')
664
@login_required
665
def send_welcome_email():
666
"""Send welcome email to new user."""
667
668
success = send_mail(
669
subject='Welcome to Our Platform!',
670
recipient=current_user.email,
671
template='welcome_email',
672
user=current_user,
673
login_url=url_for_security('login', _external=True)
674
)
675
676
if success:
677
flash('Welcome email sent successfully')
678
else:
679
flash('Failed to send welcome email')
680
681
return redirect(url_for('dashboard'))
682
683
@app.route('/send-custom-notification', methods=['POST'])
684
@roles_required('admin')
685
def send_custom_notification():
686
"""Send custom notification to users."""
687
688
subject = request.form.get('subject')
689
message = request.form.get('message')
690
recipient_emails = request.form.getlist('recipients')
691
692
sent_count = 0
693
for email in recipient_emails:
694
if mail_util.send_mail(
695
template='notification_email',
696
subject=subject,
697
recipient=email,
698
message=message,
699
admin_name=current_user.email
700
):
701
sent_count += 1
702
703
flash(f'Notification sent to {sent_count} users')
704
return redirect(url_for('admin_notifications'))
705
```
706
707
### SMS Integration
708
709
```python
710
from flask_security import SmsSenderFactory
711
712
# Configure SMS service
713
app.config['SECURITY_SMS_SERVICE'] = 'Twilio'
714
app.config['SECURITY_SMS_SERVICE_CONFIG'] = {
715
'ACCOUNT_SID': 'your-account-sid',
716
'AUTH_TOKEN': 'your-auth-token',
717
'FROM_NUMBER': '+1234567890'
718
}
719
720
# Create SMS sender
721
sms_sender = SmsSenderFactory.createSender(
722
app.config['SECURITY_SMS_SERVICE'],
723
**app.config['SECURITY_SMS_SERVICE_CONFIG']
724
)
725
726
@app.route('/send-sms-code', methods=['POST'])
727
@login_required
728
def send_sms_code():
729
"""Send SMS verification code to user."""
730
731
if not current_user.us_phone_number:
732
flash('Phone number not configured')
733
return redirect(url_for('profile'))
734
735
# Generate verification code
736
code = generate_random_code(6)
737
738
# Store code in session with expiration
739
session['sms_verification_code'] = code
740
session['sms_code_expires'] = (datetime.utcnow() + timedelta(minutes=5)).isoformat()
741
742
# Send SMS
743
message = f"Your verification code is: {code}"
744
success = sms_sender.send_sms(
745
from_number=app.config['SECURITY_SMS_SERVICE_CONFIG']['FROM_NUMBER'],
746
to_number=current_user.us_phone_number,
747
msg=message
748
)
749
750
if success:
751
flash('Verification code sent to your phone')
752
else:
753
flash('Failed to send SMS')
754
755
return redirect(url_for('verify_phone'))
756
757
def generate_random_code(length=6):
758
"""Generate random numeric code."""
759
import random
760
import string
761
return ''.join(random.choices(string.digits, k=length))
762
```
763
764
### TOTP Two-Factor Authentication
765
766
```python
767
from flask_security import Totp
768
769
@app.route('/setup-2fa')
770
@login_required
771
def setup_2fa():
772
"""Setup TOTP two-factor authentication."""
773
774
# Generate TOTP secret
775
totp = Totp()
776
777
# Store secret in session temporarily
778
session['totp_setup_secret'] = totp.secret
779
780
# Generate QR code for authenticator apps
781
qr_code = totp.generate_qr_code(
782
name=current_user.email,
783
issuer='My Secure App'
784
)
785
786
return render_template('setup_2fa.html',
787
secret=totp.secret,
788
qr_code=qr_code)
789
790
@app.route('/verify-2fa-setup', methods=['POST'])
791
@login_required
792
def verify_2fa_setup():
793
"""Verify TOTP setup with user-provided code."""
794
795
code = request.form.get('code')
796
secret = session.get('totp_setup_secret')
797
798
if not secret:
799
flash('Setup session expired')
800
return redirect(url_for('setup_2fa'))
801
802
# Verify the code
803
totp = Totp(secret=secret)
804
if totp.verify(code, window=1):
805
# Save TOTP secret to user
806
current_user.tf_totp_secret = secret
807
current_user.tf_primary_method = 'authenticator'
808
db.session.commit()
809
810
# Clear setup session
811
session.pop('totp_setup_secret', None)
812
813
flash('Two-factor authentication enabled successfully')
814
return redirect(url_for('profile'))
815
else:
816
flash('Invalid code. Please try again.')
817
return redirect(url_for('setup_2fa'))
818
819
@app.route('/verify-2fa', methods=['GET', 'POST'])
820
@login_required
821
def verify_2fa():
822
"""Verify TOTP code for authentication."""
823
824
if request.method == 'POST':
825
code = request.form.get('code')
826
827
if current_user.tf_totp_secret:
828
totp = Totp(secret=current_user.tf_totp_secret)
829
if totp.verify(code, window=1):
830
session['2fa_verified'] = True
831
return redirect(request.args.get('next', '/dashboard'))
832
else:
833
flash('Invalid authentication code')
834
835
return render_template('verify_2fa.html')
836
```
837
838
### Utility Class Integration
839
840
```python
841
from flask_security import PasswordUtil, PhoneUtil, UsernameUtil
842
843
# Initialize utility classes
844
password_util = PasswordUtil(app)
845
phone_util = PhoneUtil(app)
846
username_util = UsernameUtil(app)
847
848
@app.route('/validate-profile', methods=['POST'])
849
@login_required
850
def validate_profile():
851
"""Validate user profile data."""
852
853
username = request.form.get('username')
854
phone = request.form.get('phone')
855
new_password = request.form.get('new_password')
856
857
errors = []
858
859
# Validate username if provided
860
if username:
861
try:
862
username_util.validate_username(username)
863
normalized_username = username_util.normalize_username(username)
864
except ValidationError as e:
865
errors.append(f"Username: {e}")
866
867
# Validate phone number if provided
868
if phone:
869
if phone_util.validate_phone_number(phone):
870
normalized_phone = phone_util.normalize_phone_number(phone)
871
else:
872
errors.append("Invalid phone number format")
873
874
# Validate new password if provided
875
if new_password:
876
try:
877
password_util.validate_password(new_password)
878
except ValidationError as e:
879
errors.append(f"Password: {e}")
880
881
if errors:
882
return jsonify({'success': False, 'errors': errors})
883
884
# Update user profile
885
if username:
886
current_user.username = normalized_username
887
if phone:
888
current_user.us_phone_number = normalized_phone
889
if new_password:
890
current_user.password = password_util.hash_password(new_password)
891
892
db.session.commit()
893
894
return jsonify({'success': True, 'message': 'Profile updated successfully'})
895
```
896
897
### Custom Security Decorators Using Utilities
898
899
```python
900
from functools import wraps
901
from flask_security import get_request_attr, naive_utcnow
902
903
def rate_limit(max_requests=10, window_seconds=60):
904
"""Rate limiting decorator using utilities."""
905
906
def decorator(f):
907
@wraps(f)
908
def decorated_function(*args, **kwargs):
909
910
# Get client IP using utility
911
client_ip = get_request_attr('remote_addr') or 'unknown'
912
913
# Simple in-memory rate limiting (use Redis in production)
914
current_time = naive_utcnow()
915
916
if not hasattr(app, 'rate_limit_store'):
917
app.rate_limit_store = {}
918
919
key = f"rate_limit:{client_ip}:{f.__name__}"
920
921
if key in app.rate_limit_store:
922
requests, window_start = app.rate_limit_store[key]
923
924
# Check if window expired
925
if (current_time - window_start).total_seconds() > window_seconds:
926
# Reset window
927
app.rate_limit_store[key] = (1, current_time)
928
elif requests >= max_requests:
929
# Rate limit exceeded
930
return jsonify({'error': 'Rate limit exceeded'}), 429
931
else:
932
# Increment counter
933
app.rate_limit_store[key] = (requests + 1, window_start)
934
else:
935
# First request in window
936
app.rate_limit_store[key] = (1, current_time)
937
938
return f(*args, **kwargs)
939
return decorated_function
940
return decorator
941
942
@app.route('/api/sensitive-endpoint')
943
@login_required
944
@rate_limit(max_requests=5, window_seconds=60)
945
def sensitive_endpoint():
946
"""Rate-limited API endpoint."""
947
return jsonify({'data': 'sensitive information'})
948
```
949
950
## Configuration
951
952
Flask-Security utilities can be configured through various configuration variables:
953
954
```python
955
# Email configuration
956
app.config['MAIL_SERVER'] = 'smtp.gmail.com'
957
app.config['MAIL_PORT'] = 587
958
app.config['MAIL_USE_TLS'] = True
959
app.config['MAIL_USERNAME'] = 'your-email@gmail.com'
960
app.config['MAIL_PASSWORD'] = 'your-password'
961
962
# Password validation configuration
963
app.config['SECURITY_PASSWORD_LENGTH_MIN'] = 8
964
app.config['SECURITY_PASSWORD_COMPLEXITY_CHECKER'] = 'zxcvbn'
965
966
# Token configuration
967
app.config['SECURITY_TOKEN_AUTHENTICATION_KEY'] = 'auth_token'
968
app.config['SECURITY_TOKEN_MAX_AGE'] = 86400 # 24 hours
969
970
# SMS configuration
971
app.config['SECURITY_SMS_SERVICE'] = 'Twilio'
972
app.config['SECURITY_SMS_SERVICE_CONFIG'] = {
973
'ACCOUNT_SID': 'your-sid',
974
'AUTH_TOKEN': 'your-token'
975
}
976
```
977
978
## Security Considerations
979
980
### Token Security
981
- Use cryptographically secure random token generation
982
- Implement proper token expiration and rotation
983
- Store tokens securely with appropriate hashing
984
- Validate token signatures to prevent tampering
985
986
### Communication Security
987
- Use TLS/SSL for all email and SMS communications
988
- Validate recipient addresses before sending messages
989
- Implement rate limiting for communication endpoints
990
- Log security-related communications for audit trails
991
992
### Password Security
993
- Use strong password hashing algorithms (bcrypt, Argon2)
994
- Implement comprehensive password policies
995
- Check passwords against known breach databases
996
- Provide clear feedback on password requirements
997
998
### General Security
999
- Validate all user inputs using utility functions
1000
- Implement proper error handling without information disclosure
1001
- Use secure random number generation for codes and tokens
1002
- Monitor and log security-related utility function usage