splent_feature_auth
The auth feature of a SPLENT product line.
Accounts, login, logout and sessions. It owns the User model, the login
page, the accounts screen for administrators (/admin/users), a person's own
account page (/account), the login throttle and the password policy. Every
SPLENT product installs it.
A SPLENT feature is a Python package that a product composes with others.
Its models, routes, services, templates and hooks are registered when the
product starts. What this feature provides and requires is listed in the
[tool.splent.contract] section of pyproject.toml, which
splent feature:contract --write keeps in sync with the source.
The login page
The login page opens three slots, so other features add to it without overriding the template. A callback takes no arguments and returns HTML, or an empty string to add nothing on this request.
| Slot | Where it renders | When |
|---|---|---|
auth.login.providers |
After the submit button, under the words "or continue with" | Only when a callback returns something. Otherwise nothing is drawn, not even the words |
auth.login.error_hint |
Under the error, inside the form | Only after a wrong email or password. Never for a throttled attempt or an account that is not active, whose messages stay as they are |
auth.login.form_footer |
At the bottom of the form | Always |
A sign-in provider puts its button in auth.login.providers.
# hooks.py of a provider feature
from flask import render_template
from splent_framework.hooks.template_hooks import register_template_hook
def login_button():
return render_template("hooks/login_button.html")
register_template_hook("auth.login.providers", login_button, order=20)
A hint reads what was typed from the request.
from flask import render_template, request
def password_hint():
email = request.form.get("email", "")
if not signs_in_with_a_provider(email):
return ""
return render_template("hooks/password_hint.html")
register_template_hook("auth.login.error_hint", password_hint)
A hint that depends on the address tells whoever types it whether an account exists there. A feature that adds one should let the product turn it off.
Password policy
One rule for every place that sets a password. The accounts screen, My
account and the create-user and set-password commands apply it, and so
does any feature that sets a password and imports it. It applies when a
password is set, never at login, so an account whose password predates a
longer minimum keeps signing in.
| Setting | Default | Meaning |
|---|---|---|
AUTH_PASSWORD_MIN_LENGTH |
8 | The shortest password accepted, from 8 to 128. A value below 8 becomes 8 and one above 128 becomes 128, with a warning in the log |
AUTH_PASSWORD_CONFIRM |
false | Whether a form that sets a password asks for it twice |
No password longer than 128 characters (MAX_LENGTH) can be set, whatever
the minimum. That leaves room for a passphrase or a password manager's
output, and a form that sets a password never hashes a pasted megabyte.
AUTH_PASSWORD_CONFIRM adds a second box where a form would ask once. My
account always asks twice. The commands ask twice whenever they prompt.
A product sets them in its own [tool.splent.config].
[tool.splent.config]
AUTH_PASSWORD_MIN_LENGTH = 12
AUTH_PASSWORD_CONFIRM = true
The API lives in splent_io.splent_feature_auth.passwords.
| Name | What it does |
|---|---|
password_problem(password, confirmation=None) |
The translated reason a new password cannot be used, or None. A confirmation of None is not compared, and an empty one does not match |
PasswordPolicy(repeats=None) |
WTForms validator built on password_problem. With repeats, it checks that this field repeats the one named |
confirmation_required() |
Whether the product asks for a new password twice |
min_length() |
The shortest password the product accepts, never below MIN_LENGTH_FLOOR (8) nor above MAX_LENGTH (128) |
MAX_LENGTH |
The longest password accepted, 128 characters |
A form that sets a password.
from flask_babel import lazy_gettext as _l
from flask_wtf import FlaskForm
from wtforms import PasswordField
from wtforms.validators import DataRequired
from splent_io.splent_feature_auth.passwords import (
PasswordPolicy,
confirmation_required,
)
class SignupForm(FlaskForm):
password = PasswordField(
_l("Password"), validators=[DataRequired(), PasswordPolicy()]
)
confirm_password = PasswordField(
_l("Repeat the password"), validators=[PasswordPolicy(repeats="password")]
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not confirmation_required():
del self.confirm_password
The template draws the second box only when the form still has it, with
{% if form.confirm_password %}. A length error sits under the first box
and a mismatch under the second. Put Optional() instead of DataRequired()
on a field that may stay blank, such as a new password on an edit form.
Code that is not a form calls the helper directly.
from splent_io.splent_feature_auth.passwords import password_problem
problem = password_problem(password, request.form.get("confirm_password", ""))
if problem:
flash(problem, "danger")
Use it in a product
splent feature:add splent_feature_auth
Develop
splent feature:test splent_feature_auth
splent feature:contract splent_feature_auth
Release
splent feature:release splent_feature_auth --dry-run --bump patch
splent feature:release splent_feature_auth
The first command rehearses the release and changes nothing. The second publishes it to the git forge and to PyPI, and a PyPI version is permanent.
Metadata
Release files for splent-feature-auth 1.20.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| splent_feature_auth-1.20.0.tar.gz | 63.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| splent_feature_auth-1.20.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 142.1 kB
Release files / splent_feature_auth-1.20.0.tar.gz
| Download URL | splent_feature_auth-1.20.0.tar.gz |
|---|---|
| Size | 63.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3b8cb974040d2f719081210d6a96e565102bbde3194c6c340611f9f759eec669
|
|
BLAKE2b-256 checksum How to use checksums |
f38b1b0c34baaead70508492c806f0f3afa3dcc5515766a22ef2ec65c326b91c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.13
|
Release files / splent_feature_auth-1.20.0-py3-none-any.whl
| Download URL | splent_feature_auth-1.20.0-py3-none-any.whl |
|---|---|
| Size | 78.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e3e2306f3ceb1442d9bb623796c5f6865f5fa24381c2e6fcffd0d70cf5d031b2
|
|
BLAKE2b-256 checksum How to use checksums |
248f24379f6f62b104b56e0615b84e5357ed63b7315119b7ee132b5decdfab13
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.13
|
Security for splent-feature-auth 1.20.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.