anicove / api /utils /mobile_auth.py
mwask's picture
Upload 403 files
72b125b verified
Raw History Blame Contribute Delete
1.74 kB
"""Bearer-token auth for the mobile app (Flask sessions are unreliable on native clients)."""
from flask import current_app, request, session
from itsdangerous import BadSignature, SignatureExpired, URLSafeTimedSerializer
TOKEN_SALT = "anicove-mobile-auth"
TOKEN_MAX_AGE = 30 * 24 * 60 * 60
def _serializer():
return URLSafeTimedSerializer(current_app.config["SECRET_KEY"], salt=TOKEN_SALT)
def issue_mobile_token(user_id, username, avatar=None):
return _serializer().dumps({
"user_id": str(user_id),
"username": username,
"avatar": avatar,
})
def parse_mobile_token(token):
try:
return _serializer().loads(token, max_age=TOKEN_MAX_AGE)
except (BadSignature, SignatureExpired, TypeError, ValueError):
return None
def require_mobile_auth():
"""Return (user_id, username, avatar) from session or Bearer token."""
if session.get("username") and session.get("_id") is not None:
return str(session["_id"]), session["username"], session.get("avatar")
header = request.headers.get("Authorization") or ""
token = ""
if header.lower().startswith("bearer "):
token = header.split(" ", 1)[1].strip()
if not token:
token = (request.headers.get("X-Auth-Token") or "").strip()
if not token:
data = request.get_json(silent=True) or {}
token = str(data.get("token") or request.args.get("token") or "").strip()
if not token:
return None
payload = parse_mobile_token(token)
if not payload or not payload.get("user_id") or not payload.get("username"):
return None
return str(payload["user_id"]), payload["username"], payload.get("avatar")