Introduction
Authentication and authorization form the foundation of application security. Understanding these concepts and their implementation is crucial for building secure applications. This guide covers everything from basic concepts to implementation.
Authentication Fundamentals
What Is Authentication
Authentication verifies identityโproving you are who you claim to be.
Common Methods
| Method | Description | Use Cases |
|---|---|---|
| Password | Something you know | Most applications |
| Biometric | Something you are | Mobile, high security |
| Token | Something you have | API access |
| Multi-factor | Combination | High security |
Password-Based Authentication
Best Practices
- Never store passwords in plain text
- Use strong hashing algorithms
- Enforce password complexity
- Implement rate limiting
Password Hashing
import bcrypt
# Hashing
def hash_password(password):
salt = bcrypt.gensalt()
return bcrypt.hashpw(password.encode(), salt)
# Verifying
def verify_password(password, hashed):
return bcrypt.checkpw(password.encode(), hashed)
Using hashing Libraries
# Argon2 (recommended)
from argon2 import PasswordHasher
ph = PasswordHasher()
hash = ph.hash("password123")
ph.verify(hash, "password123")
# PBKDF2 (widely supported)
import hashlib, binascii
def pbkdf2_hash(password, salt=None):
if not salt:
salt = binascii.unhexlify(os.urandom(32))
key = hashlib.pbkdf2_hmac('sha256', password.encode(), salt, 100000)
return salt + key
Token-Based Authentication
JSON Web Tokens (JWT)
Structure:
xxxxx.yyyyy.zzzzz
Header.Payload.Signature
Creating JWT:
import jwt
import datetime
def create_token(user_id):
payload = {
'user_id': user_id,
'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=24),
'iat': datetime.datetime.utcnow()
}
return jwt.encode(payload, 'SECRET_KEY', algorithm='HS256')
Verifying JWT:
def verify_token(token):
try:
payload = jwt.decode(token, 'SECRET_KEY', algorithms=['HS256'])
return payload
except jwt.ExpiredSignatureError:
return None
Access Tokens vs Refresh Tokens
- Access Token: Short-lived, for API requests
- Refresh Token: Long-lived, for obtaining new access tokens
OAuth 2.0
OAuth Flow
# 1. Redirect to authorization
auth_url = (
"https://authorization-server.com/authorize"
"?response_type=code"
f"&client_id={CLIENT_ID}"
f"&redirect_uri={REDIRECT_URI}"
f"&scope=read:profile"
)
# 2. Exchange code for token
import requests
response = requests.post('https://authorization-server.com/token', data={
'grant_type': 'authorization_code',
'code': authorization_code,
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'redirect_uri': REDIRECT_URI,
})
token = response.json()['access_token']
Grant Types
- Authorization Code: Web applications
- Client Credentials: Machine-to-machine
- Device Code: Input-constrained devices
- Refresh Token: Obtaining new access tokens
OpenID Connect (OIDC)
Built on OAuth 2.0 for authentication:
# ID Token verification
from google.oauth2 import id_token
from google.auth.transport import requests as google_requests
idinfo = id_token.verify_oauth2_token(
token,
google_requests.Request(),
CLIENT_ID
)
Session Management
Server-Side Sessions
from flask import Flask, session
import secrets
app = Flask(__name__)
app.secret_key = secrets.token_hex(32)
@app.route('/login', methods=['POST'])
def login():
session['user_id'] = user.id
session.permanent = True
return 'Logged in'
@app.route('/logout')
def logout():
session.clear()
return 'Logged out'
@app.route('/profile')
def profile():
if 'user_id' not in session:
return 'Unauthorized', 401
return f'Welcome {session["user_id"]}'
Session Security
# Secure session configuration
app.config.update(
SESSION_COOKIE_SECURE=True,
SESSION_COOKIE_HTTPONLY=True,
SESSION_COOKIE_SAMESITE='Lax',
)
Authorization
What Is Authorization
Authorization determines what an authenticated user can do.
RBAC (Role-Based Access Control)
ROLES = {
'admin': ['read', 'write', 'delete', 'admin'],
'moderator': ['read', 'write'],
'user': ['read'],
'guest': []
}
def check_permission(role, action):
return action in ROLES.get(role, [])
Implementing RBAC
from functools import wraps
def require_permission(permission):
def decorator(f):
@wraps(f)
def decorated(*args, **kwargs):
if not check_permission(current_user.role, permission):
return 'Forbidden', 403
return f(*args, **kwargs)
return decorated
return decorator
@app.route('/delete')
@require_permission('delete')
def delete():
pass
ABAC (Attribute-Based Access Control)
def can_access(user, resource, action):
# Check time
if resource.requires_office_hours:
if not is_office_hours():
return False
# Check department
if resource.department != user.department:
if not user.has_role('admin'):
return False
return True
API Keys
Generating and Using
import secrets
def generate_api_key():
return f"sk_{secrets.token_urlsafe(32)}"
# Store hash, not the key itself
def hash_api_key(key):
return hashlib.sha256(key.encode()).hexdigest()
# Middleware for verification
def verify_api_key(request):
key = request.headers.get('X-API-Key')
if not key:
return None
key_hash = hash_api_key(key)
stored = get_key_from_db(key_hash)
if stored and stored.is_active:
return stored.user
return None
Multi-Factor Authentication (MFA)
TOTP (Time-based One-Time Password)
import pyotp
# Generate secret
secret = pyotp.random_base32()
# Generate QR URI for authenticator app
totp_uri = pyotp.totp.TOTP(secret).provisioning_uri(
name='[email protected]',
issuer_name='MyApp'
)
# Verify
totp = pyotp.TOTP(secret)
code = input("Enter code: ")
print(totp.verify(code))
Implementing MFA
@app.route('/verify-mfa', methods=['POST'])
def verify_mfa():
code = request.form['code']
user = get_current_user()
totp = pyotp.TOTP(user.mfa_secret)
if not totp.verify(code):
return 'Invalid code', 401
# Mark session as MFA verified
session['mfa_verified'] = True
return 'OK'
Passkeys and FIDO2
What Are Passkeys?
Passkeys are passwordless authentication credentials based on FIDO2 standards:
// Register a passkey
async function registerPasskey() {
const credential = await navigator.credentials.create({
publicKey: {
challenge: serverChallenge,
rp: {
name: 'My Application',
id: window.location.hostname
},
user: {
id: userIdBuffer,
name: user.name,
displayName: user.displayName
},
pubKeyCredParams: [
{ type: 'public-key', alg: -7 },
{ type: 'public-key', alg: -257 }
],
authenticatorSelection: {
userVerification: 'required'
}
}
});
// Send credential to server
await fetch('/auth/passkey/register', {
method: 'POST',
body: JSON.stringify(credential)
});
}
Authenticate with Passkey
// Authenticate with passkey
async function authenticateWithPasskey() {
const assertion = await navigator.credentials.get({
publicKey: {
challenge: serverChallenge,
rpId: window.location.hostname,
userVerification: 'required'
}
});
// Verify with server
await fetch('/auth/passkey/login', {
method: 'POST',
body: JSON.stringify(assertion)
});
}
Passkey Server Implementation
# Passkey registration
import json
from cryptography.hazmat.primitives import serialization
from fido2 import ctap2
from fido2.server import Fido2Server
class PasskeyServer:
def __init__(self, relying_party_id):
self.server = Fido2Server(
{"id": relying_party_id, "name": "My App"}
)
def register_begin(self, user_id, user_name):
options, state = self.server.register_begin(
{
"id": user_id.encode(),
"name": user_name,
"displayName": user_name
},
authenticator_attachment="cross-platform"
)
return options, state
def register_complete(self, state, client_data, attestation):
auth_data = self.server.register_complete(
state, client_data, attestation
)
# Store credential ID and public key
return auth_data
Best Practices
Security Checklist
- Use HTTPS everywhere
- Implement rate limiting
- Use secure password hashing (bcrypt/argon2)
- Implement MFA for sensitive operations
- Use short-lived access tokens
- Store refresh tokens securely
- Log authentication events
- Implement account lockout
- Adopt passkeys for passwordless
- Use FIDO2/WebAuthn for high security
- Implement credential manager support
- Enable device fingerprinting
Common Vulnerabilities
- SQL Injection: Use parameterized queries
- XSS: Sanitize output
- CSRF: Use anti-CSRF tokens
- Session Hijacking: Use secure cookies
- Token Leakage: Store tokens securely, use short lifespans
- Replay Attacks: Use nonces and timestamps
Conclusion
Authentication and authorization are fundamental to application security. Use established protocols (OAuth 2.0, OIDC), implement proper token handling, follow the principle of least privilege, and adopt passwordless authentication where possible. Security is not optional.
2026 recommendations:
- Passkeys: Replace passwords with FIDO2 passkeys
- Passwordless: WebAuthn for modern authentication
- OAuth 2.1: Latest protocol improvements
- Short tokens: Minimize token lifetime
- Continuous verification: Device and behavior analysis
Conclusion
Authentication and authorization are fundamental to application security. Use established protocols (OAuth 2.0, OIDC), implement proper token handling, and follow the principle of least privilege. Security is not optional.
Comments