Skip to main content

splent_feature_apikeys

Developer API tokens for a SPLENT product. A port of the UVLHub apikeys feature to SPLENT conventions, and the only place in a product where a password is exchanged for a credential a machine can carry.

It owns tokens and nothing else. It does not know what the tokens are used for, and it never touches the auth feature: credentials are checked through the AuthenticationService that auth already registers.

The model

ApiToken belongs to one user and keeps:

Column Meaning
user_id Owner, foreign key to auth's user.id
name Human label chosen by the owner
token_hash sha256 of the plaintext, hex. The plaintext is never stored
prefix First 15 characters of the plaintext, indexed, safe to show
scopes Comma separated, as in UVLHub
created_at, expires_at, revoked_at, last_used_at lifecycle

A plaintext token looks like splent_<64 hex characters>. The splent_ label makes a leaked token greppable; the prefix makes verification a single indexed lookup instead of a table scan.

Scopes

read_spl and write_spl. Unknown names are dropped, and a request that asks for nothing but unknown names is refused rather than silently producing a token that can do nothing.

The service

ApiTokenService, registered under that name in the service locator.

api_token_service = service_proxy("ApiTokenService")

row, plaintext = api_token_service.mint(user, "laptop", ["write_spl"], ttl_days=90)
api_token_service.verify(plaintext)       # row, or None if unknown/revoked/expired
api_token_service.find(plaintext)         # row whatever its state, to explain a refusal
api_token_service.revoke(row.id, user)    # only the owner can revoke
api_token_service.touch(row)              # last_used_at, at most once every 5 minutes
api_token_service.authenticate(email, password)  # (user, None) or (None, reason)

mint returns the plaintext once. Nothing else in the product can ever produce it again.

Guarding a route

from splent_io.splent_feature_apikeys.decorators import require_token

@some_bp.route("/api/v1/spls", methods=["POST"])
@require_token("write_spl")
def publish():
    g.api_user   # the owner
    g.api_token  # the presenting token

require_token() with no scope accepts any usable token. For routes where a token is one of several ways in, call resolve_token(scope) directly: it returns (api_token, None) or (None, (response, status)).

Endpoints

Method Path Auth
POST /api/v1/auth/tokens email + password
GET /api/v1/auth/whoami Bearer token
DELETE /api/v1/auth/tokens/current Bearer token
curl -X POST https://<product>/api/v1/auth/tokens \
     -H "Content-Type: application/json" \
     -d '{"email": "dev@example.com", "password": "...", "name": "laptop"}'

curl https://<product>/api/v1/auth/whoami \
     -H "Authorization: Bearer splent_..."

Omitting ttl_days gives the product default; sending it as null gives a token that never expires.

Failed credential attempts are throttled per caller and account. Users are created inactive and an administrator activates them, so an account still waiting is answered with 403 and a message that says exactly that, never with "wrong password".

Pages

  • /developer/tokens — the owner's tokens, by prefix, with a revoke button.
  • /developer/tokens/new — create one; the plaintext is shown once.

A link appears in the authenticated sidebar (layout.authenticated_sidebar hook).

Configuration

Variable Default Meaning
APIKEYS_DEFAULT_TTL_DAYS 90 Life of a token when none is asked
APIKEYS_MAX_LOGIN_ATTEMPTS 5 Failed attempts per window
APIKEYS_LOGIN_WINDOW_SECONDS 300 Length of that window

All three have working defaults, so the feature needs no .env entry.

Install

splent feature:install splent-io/splent_feature_apikeys
splent db:migrate splent_feature_apikeys
splent db:upgrade

Tests

splent feature:test splent_feature_apikeys

Metadata

Release files for splent-feature-apikeys 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for splent-feature-apikeys 0.1.1
File Size Uploaded Provenance
splent_feature_apikeys-0.1.1.tar.gz 24.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for splent-feature-apikeys 0.1.1
File Interpreter ABI Platform
splent_feature_apikeys-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 54.8 kB

Release files / splent_feature_apikeys-0.1.1.tar.gz

Download URL splent_feature_apikeys-0.1.1.tar.gz
Size 24.0 kB
Tags Source
SHA-256 checksum
How to use checksums
2217107acda34fa6032cf1a0baed3b44bfad8acc34b6a3d5e157e8a73d826826
BLAKE2b-256 checksum
How to use checksums
57e70a950db45b292294248580c8924cb06d905cb2e0a911a8ca94dab380e615
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / splent_feature_apikeys-0.1.1-py3-none-any.whl

Download URL splent_feature_apikeys-0.1.1-py3-none-any.whl
Size 30.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d5effd6d56714e9429972ea4f60cc8ea277eaa99d371b045923f6f25e2ff6d54
BLAKE2b-256 checksum
How to use checksums
e828c9cf874625ea8fb4f5081c2b2c13711f04f24c17bfc916c2e6423f47f06a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Security for splent-feature-apikeys 0.1.1

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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page