You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/app/content/docs/framework/auth.md
+31-21Lines changed: 31 additions & 21 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -10,24 +10,27 @@ SPRAG includes a built-in auth surface for session management and access control
10
10
11
11
## Setup
12
12
13
-
Wire auth providers into your App:
13
+
Wire auth providers into your `App`. SPRAG looks for `session_store` and `auth` in `app.providers`, and falls back to in-memory sessions plus anonymous auth if you do not provide them:
14
14
15
15
```python
16
-
from sprag import App, shell
17
-
from sprag import InMemorySessionStore, AnonymousAuthService
16
+
from sprag import App, InMemorySessionStore, SessionPolicy
18
17
19
18
app = App(
20
19
routes="app.routes",
21
-
shell=app_shell,
22
20
providers={
23
21
"session_store": InMemorySessionStore(),
24
-
"auth": AnonymousAuthService(),
22
+
"auth": MyAuthService(),
25
23
},
24
+
session_policy=SessionPolicy(
25
+
idle_ttl_seconds=3600,
26
+
absolute_ttl_seconds=86400,
27
+
remember_me_ttl_seconds=2592000,
28
+
),
26
29
)
27
30
```
28
31
29
32
-**`InMemorySessionStore`** — stores sessions in memory. Fine for development; swap for Redis/database-backed store in production.
30
-
-**`AnonymousAuthService`** — no-op auth that treats every request as unauthenticated. Replace with your auth provider.
33
+
-**`auth` provider** — implements user loading, login session stamping, authorization, and the public auth snapshot.
self.request.user # Authenticated user object (or None)
64
-
self.request.session #Session dict
67
+
self.request.session #RequestSession helper
65
68
self.request.session_id # Session ID string
69
+
self.request.active_profile # Active profile object (or None)
66
70
self.request.cookies # Request cookies
67
71
```
68
72
@@ -102,30 +106,36 @@ class ProfileController(Controller):
102
106
103
107
## Browser-side auth
104
108
105
-
The auth state is included in the browser boot payload at `window.__SPRAG_PAYLOAD__.auth`. Your Module can read it to conditionally render UI:
109
+
SPRAG injects an auth snapshot into route data under `__sprag_auth__`. That same snapshot is also shipped in the browser boot payload, but the stable author-facing name in route data is `__sprag_auth__`:
-**`document`** — Pure SSR. The server renders HTML and sends it. No JavaScript is loaded. Best for content pages, marketing pages, and anything that doesn't need interactivity.
136
+
-**`document`** — Server-first rendering for content-heavy pages. The route still ships the standard SPRAG boot payload, but you typically avoid browser-owned Module logic here.
136
137
137
138
-**`hybrid`** — SSR first, then hydrate. The server renders the initial HTML for a fast first paint, then the browser loads JavaScript to make it interactive. This is the default and the right choice for most pages.
138
139
139
-
-**`mount`** — No SSR body. The server sends a shell, and the browser mounts everything. Use when the page content is entirely dynamic (dashboards, editors, etc.).
140
+
If you want a browser-owned client app instead of a page route, use `mount(...)` under `app/mounts/`. Mounts are separate from page modes.
140
141
141
142
## Dynamic routes
142
143
@@ -155,7 +156,7 @@ from .web import BlogScreen
155
156
from app.content import blog_static_paths
156
157
157
158
blog_page = page(
158
-
path="/blog/:slug",
159
+
path="/blog/[slug]",
159
160
controller=BlogController,
160
161
screen=BlogScreen,
161
162
mode="document",
@@ -186,4 +187,4 @@ sprag add route about --mode document
186
187
sprag routes
187
188
```
188
189
189
-
This prints all discovered routes, their modes, and tags like `[socket]` for controllers that use the socket bridge.
190
+
This prints discovered routes, mounts, actions, and any schema fields declared on those actions.
`self.subscribe()` auto-cleans on Module stop — no manual unsubscribe needed.
82
89
83
90
## When to use stores
84
91
85
-
**Use `store()`** for state that needs to be shared across routes or between multiple components/modules in the same page. Stores persist across navigations on the server and are reactive on the browser.
92
+
**Use `store()`** for state that needs to be shared across routes or between multiple components/modules in the same page. It gives you one authoring surface backed by Specter on the server and a generated store shim in the browser.
86
93
87
94
**Use controller state** (the dict from `load()`) for per-page state that lives within a single route. This is simpler and covers most cases.
Copy file name to clipboardExpand all lines: docs/app/content/docs/framework/two-runtimes.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -43,7 +43,7 @@ These patterns are intentionally identical across runtimes:
43
43
Each runtime owns its boundary:
44
44
45
45
-**DOM** — browser only. Components render `ui.*` trees; the server never touches the DOM.
46
-
-**Sockets** — the server *sends* socket events, the browser *receives* them. The Module has `on_socket()`; the Controller has`emit_socket()`.
46
+
-**Sockets** — both runtimes can participate through the shared socket bridge. Controllers can emit and handle socket traffic; Modules can subscribe with `on_socket()` and emit with`emit_socket()`.
47
47
-**HTTP** — the server handles requests. The browser calls `call_action()` to invoke server actions over HTTP.
48
48
-**File system** — server only. The browser has no access.
0 commit comments