Conversation
The best way to use the API is one deployment per project, the example should reflect that.
This is required for this endpoint, but this endpoint is likely unused. We'll remove it when we're sure.
To differentiate from invalid input (no credentials) or unverified user
|
Could we add a session probe GET endpoint that the frontend can use to validate the current access-token session? There are some auth protected routes in the frontend that currently don't make any backend requests, so they can have stale auth information. Ideally the endpoint would live outside For example a from flask import Blueprint, jsonify
from flask_jwt_extended import jwt_required, get_jwt, get_jwt_identity
from sls_api import rate_limiter
from sls_api.models import User
"""
Session probe endpoints for frontend authentication checks.
These routes are intentionally outside `/auth/*` so frontend request
interceptors can attach access tokens and run refresh logic uniformly.
"""
session = Blueprint('session', __name__, url_prefix="/session")
def _invalid_credentials_response():
response = jsonify({"msg": "Invalid credentials", "err": "INCORRECT_CREDENTIALS"})
response.headers["Cache-Control"] = "no-store"
response.headers["Pragma"] = "no-cache"
return response, 401
@session.route("/validate", methods=["GET"])
@rate_limiter.limit("60/minute")
@jwt_required() # access token required
def validate_session():
"""
Validate current access-token session.
Returns 200 only when the token is valid, not invalidated, and the
user's email is verified. Returns 401 for all invalid states.
"""
claims = get_jwt()
identity = get_jwt_identity()
jwt_issued_at = claims.get("iat")
user = User.find_by_email(identity)
if not user:
return _invalid_credentials_response()
if not jwt_issued_at:
return _invalid_credentials_response()
# Reject invalidated tokens
if not User.check_token_validity(identity, jwt_issued_at):
return _invalid_credentials_response()
# Unverified users are treated as unauthorized for app session
if not user.email_is_verified():
return _invalid_credentials_response()
response = jsonify({"authenticated": True})
response.headers["Cache-Control"] = "no-store"
response.headers["Pragma"] = "no-cache"
return response, 200 |
|
In theory, yes. But in practice, Would you prefer we extend |
I'd prefer to remove |
This way we avoid having as much configuration stored in __init__.py
Flake8 in GH actions is pickier than normal for some reason.
This PR extends the authentication system in the API to have 3 levels of access:
@reader_auth_required()wrapper, which does nothing unless the API config hasreader_auth_required: True, at which point JWT login with a user account with a verified email address is required@reader_auth_requiredbut also access to sometoolsendpoints that don't change data. Endpoints are protected by a@cms_required()wrapper, which checks that the logged in user has thecms_userflag set in the auth databasetoolsendpoints which add, edit, or delete data. Endpoints are protected by a@cms_required(edit=True)wrapper, which checks that the logged in user has thecms_userflag set, and has access to the project they are trying to edit.To support this feature, this PR also implements the following:
cms_userboolean in the users auth table, to show that a user is a CMS user and should have at least CMS read accessemail_verifiedboolean in the users auth table, to show that a user's email has been verifiedauth/verify_emailendpoint, which is protected by a fresh JWT access token requirementauth/forgot_passwordendpoint with their email in the JSON body of the request.auth/reset_passwordendpoint, with the user's new password in the JSON body of the request, and the fresh JWT token from the link in the query parameterscreated_timestampandlast_login_timestampfields for the user auth table