| name | uvicore-config-and-auth |
| description | Configuration and authentication for a Uvicore app — the package-vs-app config split, env() variables, concern config files, accessing config at runtime, overriding other packages' config/IoC bindings, HTTP middleware, and auth (Guards, scopes/permissions, the current user, the Authentication middleware). Use when working with config, middleware, permissions, or login in a Uvicore application. |
| user-invocable | true |
Uvicore Config & Auth
Configuration
The two-file split
The package-vs-app split (config/package.py = always loaded; config/app.py = only when this
package is the running app) is covered field-by-field in CLAUDE.md and uvicore-app-structure.
Two things to carry into config work here:
- Runtime access: package config at
uvicore.config['acme.appstub'] (or self.package.config
inside the provider); app config at uvicore.config.app.*.
- Both aggregate smaller concern files (
http.py, database.py, auth.py, mail.py,
cache.py, logger.py, overrides.py, dependencies.py). Put new settings in the matching
concern file, not inline in code.
env() — environment values
from uvicore.configuration import env
env('APP_NAME', 'Appstub App')
env.bool('DEBUG', False)
env.int('SERVER_PORT', 5000)
env.list('CORS_ALLOW_ORIGINS', [...])
Edit .env (copied from .env-example at install) for machine-specific values. Never hardcode
environment-specific values — wrap them in env() in a config file.
Reading config at runtime
uvicore.config.app.name
uvicore.config.app.api.auto_api
uvicore.config['acme.appstub'].version
uvicore.config.dotget('app.web.prefix')
self.package.config.web.prefix
Config is a deep-merged Dict (SuperDict) — use .dotget()/attribute access; missing keys return
empty, not errors.
Overriding ANOTHER package's config or classes
This is a superpower of Uvicore — your app can reshape framework/3rd-party packages.
- Config override (deep-merge into another package's config) in your provider
register():
self.configs([
{'key': self.name, 'value': self.package_config},
{'key': 'uvicore.auth', 'module': 'acme.appstub.config.packages.auth.config'},
])
- IoC binding / provider overrides in
config/app.py overrides:
overrides = {
'providers': { ... },
'ioc_bindings': {
'uvicore.auth.models.user.User': 'acme.appstub.models.user.User',
},
}
Your override class can subclass the original (the framework binds the original under a _BASE
name to avoid circular imports). See config/overrides.py.
Authentication & Authorization
The model
- An Authentication middleware runs per request, tries configured authenticators (e.g. Basic,
JWT), and populates
request.user / request.scope['user'] with a UserInfo (anonymous if not
logged in). Enable it per route-type in config/app.py web.middleware / api.middleware
(commented out by default) and configure mechanisms in config/auth.py.
- Guards/scopes enforce permissions on routes. A user must have ALL listed scopes (AND
logic); a superadmin bypasses every check.
Applying guards (4 equivalent levels)
- Class-level on a Routes/Controller class (applies to all its routes + children — preferred
for whole sections):
class Admin(Controller):
scopes = ['authenticated', 'admin']
- Per-route shorthand:
@route.get('/x', scopes=['post.read']).
- Per-route auth:
@route.get('/x', auth=Guard(['post.read'])).
- Per-route middleware:
@route.get('/x', middleware=[Guard(['post.read'])]).
Getting the current user
from uvicore.auth import UserInfo
from uvicore.http.routing import Guard
@route.get('/me')
async def me(request: Request, user: UserInfo = Guard(['authenticated'])):
return response.JSON({'email': user.email})
@route.get('/me2', scopes=['authenticated'])
async def me2(request: Request):
user: UserInfo = request.scope['user']
UserInfo exposes id, uuid, username, email, first_name, last_name, groups, roles, permissions, superadmin, authenticated, helpers like is_admin/is_authenticated, and user.can(perms).
Route groups with scopes
@route.group('/admin', scopes=['authenticated'])
def admin():
route.controller('dashboard')
Auto-API permissions
The automatic model CRUD API (see uvicore-api) defaults to {tablename}.{create|read|update| delete} scopes per model. Tune via config/app.py api.auto_api.scopes (List, per-verb dict, or
[] for public) and include/exclude.
Checklist