Skip to main content
โšก Calmops

Understanding Authentication and Authorization 2026

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.


Resources

Comments