Auth (campus.auth)¶
The /auth/v1 service: OAuth tokens and device flow, login sessions,
auth sessions, OAuth clients, user/credential management, vaults,
grants, connections, and the token broker. The lanes are described
narratively in Authentication.
campus.model.* types referenced here are documented in the
campus repo.
AuthRoot (token facade)¶
campus_python.auth.v1.AuthRoot
¶
Bases: ResourceRoot
Campus Auth resource.
Source code in campus_python/auth/v1/__init__.py
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 | |
url_prefix: str = '/auth/v1'
class-attribute
instance-attribute
¶
broker: broker.Broker
property
¶
Get the token broker resource.
clients: clients.Clients
property
¶
Get the clients resource.
connections: connections.Connections
property
¶
Get the connections resource.
credentials: credentials.Credentials
property
¶
Get the credentials resource.
logins: logins.LoginSessions
property
¶
Get the logins resource.
oauth: oauth.OAuth
property
¶
Get the OAuth resource for device authorization flow.
root: root.Root
property
¶
Get the root resource.
sessions: sessions.CampusSessions
property
¶
Get the sessions resource.
users: users.Users
property
¶
Get the users resource.
grants: grants.Grants
property
¶
Get the access-grant store resource.
vaults: vaults.Vaults
property
¶
Get the vaults resource.
__init__(json_client: JsonClient)
¶
Source code in campus_python/auth/v1/__init__.py
34 35 36 37 38 39 40 41 42 43 44 45 46 | |
exchange_code_for_token(code: str, redirect_uri: str) -> campus.model.OAuthToken
¶
Exchange authorization code for access token.
Makes POST request to /auth/v1/token which atomically: - Validates the authorization code - Gets or creates credentials for the user - Issues a new token or reuses existing valid token - Stores the token in credentials - Returns the token
Note: Credential storage is handled automatically by the token endpoint.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
code
|
str
|
The authorization code from OAuth callback |
required |
redirect_uri
|
str
|
The redirect URI used in the auth session |
required |
Returns:
| Type | Description |
|---|---|
OAuthToken
|
OAuthToken containing access token and metadata |
Raises:
| Type | Description |
|---|---|
AuthenticationError
|
If code is invalid or token exchange fails |
Source code in campus_python/auth/v1/__init__.py
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | |
get_token() -> campus.model.OAuthToken
¶
Convenience method to get access token for a user.
Re-acquires the login session user's campus bearer via
POST /logins/
Returns:
| Type | Description |
|---|---|
OAuthToken
|
OAuthToken for the user |
Raises:
| Type | Description |
|---|---|
AuthenticationError
|
If no login session is present |
APIError
|
invalid_grant if the login session or the user's campus grant is gone — re-login required |
Example
In a protected view that needs the user's token¶
token = campus.auth.get_token() headers = {"Authorization": f"Bearer {token.id}"} response = requests.get("https://api.example.com/data", headers=headers)
Source code in campus_python/auth/v1/__init__.py
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | |
token(grant_type: Literal['client_credentials', 'refresh_token'], *, refresh_token: str | None = None, client_id: str | None = None) -> campus.model.OAuthToken
¶
Get OAuth token from the token endpoint.
Targets the RFC 6749 token endpoint (/auth/v1/oauth/token, campus/auth/routes/oauth.py), which serves the device_code, refresh_token, and client_credentials grants — NOT the authorization-code session endpoint at /auth/v1/token (campus/auth/provider.py), whose contract requires code and redirect_uri and rejects every other grant type (#60).
The path passed to the client is relative (like every other
resource method): CampusRequest._build_url() prepends the
client's base_url itself, so an absolute URL here would be
double-prefixed into https://host/https://host/... and 404
against real deployments.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
grant_type
|
Literal['client_credentials', 'refresh_token']
|
"client_credentials" or "refresh_token". |
required |
refresh_token
|
str | None
|
The refresh token to present (refresh_token grant). |
None
|
client_id
|
str | None
|
The OAuth client the grant is made as. The token endpoint requires client_id for every grant (campus auth/routes/oauth.py token()), including refresh_token; defaults to CLIENT_ID from the environment (server mode). Public clients without CLIENT_ID configured must pass it explicitly (issue #87). |
None
|
Source code in campus_python/auth/v1/__init__.py
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 | |
refresh(stored: campus.model.OAuthToken, *, client_id: str | None = None) -> campus.model.OAuthToken
¶
Refresh an OAuth token pair (RFC 6749 section 6).
Takes a stored token and returns the rotated pair issued by the server: a new access token with a new refresh token. The presented refresh token is single-use — refresh-token grants rotate server-side (campus/auth/routes/oauth.py _handle_refresh_token_grant) — so the returned token must be persisted before the stale one is presented again.
This is the public-client entry point (issue #87): it needs no client secret, only the client_id the stored token was issued to. Error responses (invalid_grant, invalid_client, ...) raise APIError subclasses carrying the OAuth error code in details, readable via APIError.oauth_error.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stored
|
OAuthToken
|
The stored OAuthToken whose refresh token is presented to the server. |
required |
client_id
|
str | None
|
The OAuth client the token was issued to; defaults to CLIENT_ID from the environment (server mode). |
None
|
Returns:
| Type | Description |
|---|---|
OAuthToken
|
The refreshed OAuthToken (new access + refresh tokens). |
Source code in campus_python/auth/v1/__init__.py
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 | |
OAuth (device flow, revoke)¶
campus_python.auth.v1.oauth.OAuth
¶
Bases: ResourceRoot
OAuth 2.0 Device Authorization Flow resource.
Provides methods for device authorization flow used by CLI and other applications with limited input capabilities.
Reference: https://datatracker.ietf.org/doc/html/rfc8628
Source code in campus_python/auth/v1/oauth.py
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | |
url_prefix = '/auth/v1/oauth'
class-attribute
instance-attribute
¶
__init__(root: ResourceRoot)
¶
Source code in campus_python/auth/v1/oauth.py
91 92 93 | |
request_device_code(client_id: str) -> dict
¶
Request a device code for the device authorization flow.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client_id
|
str
|
The OAuth client ID (e.g., "campus-cli") |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Dict containing: |
dict
|
|
dict
|
|
dict
|
|
dict
|
|
dict
|
|
dict
|
|
Raises:
| Type | Description |
|---|---|
AuthenticationError
|
If client_id is invalid |
Source code in campus_python/auth/v1/oauth.py
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | |
poll_for_token(client_id: str, device_code: str) -> dict
¶
Poll the token endpoint for an access token.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client_id
|
str
|
The OAuth client ID |
required |
device_code
|
str
|
The device code received from request_device_code() |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Dict containing: |
dict
|
|
dict
|
|
dict
|
|
dict
|
|
dict
|
|
Raises:
| Type | Description |
|---|---|
AuthenticationError
|
With specific error codes: |
-authorization_pending
|
User hasn't completed auth yet |
-slow_down
|
Client is polling too fast |
-expired_token
|
Device code has expired |
-access_denied
|
User denied the authorization |
Source code in campus_python/auth/v1/oauth.py
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 | |
wait_for_token(client_id: str, device_code: str, *, interval: int | None = None, max_attempts: int = 60, on_pending: Callable[[], None] | None = None, sleep: Callable[[float], None] = time.sleep) -> dict
¶
Poll the token endpoint until the device is authorized.
Implements the polling loop RFC 8628 §3.5 clients must run on top of poll_for_token(): authorization_pending keeps polling, slow_down raises the interval by SLOW_DOWN_ADJUSTMENT seconds with the raised interval persisting for the remainder of the flow, network failures are retried on non-final attempts, and every other error (expired_token, access_denied, unknown) is fatal. See the parity table in this module's docstring.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client_id
|
str
|
The OAuth client ID (e.g., "campus-cli") |
required |
device_code
|
str
|
The device code from request_device_code() |
required |
interval
|
int | None
|
Minimum seconds between poll attempts, from the request_device_code() response. Defaults to DEFAULT_POLL_INTERVAL when absent or zero. |
None
|
max_attempts
|
int
|
Maximum number of poll attempts; callers typically derive this from the device code's expires_in. |
60
|
on_pending
|
Callable[[], None] | None
|
Invoked after each authorization_pending response, for progress reporting (e.g. printing a dot per poll). |
None
|
sleep
|
Callable[[float], None]
|
The sleep function; injectable for tests. |
sleep
|
Returns:
| Type | Description |
|---|---|
dict
|
The token response dict (access_token, refresh_token, ...), |
dict
|
as returned by poll_for_token(). |
Raises:
| Type | Description |
|---|---|
AuthenticationError
|
On fatal OAuth errors or when max_attempts is exhausted without authorization. |
ServerError
|
When the final attempt fails at the network/5xx level. |
Source code in campus_python/auth/v1/oauth.py
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | |
authorize_device(user_code: str, user_id: str) -> dict
¶
Authorize a device code with a user ID.
This is called by the verification page when a user submits their user code.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_code
|
str
|
The user code from the CLI |
required |
user_id
|
str
|
The user ID of the authorizing user |
required |
Returns:
| Type | Description |
|---|---|
dict
|
Dict with success status |
Raises:
| Type | Description |
|---|---|
NotFoundError
|
If user_code is invalid or expired |
ConflictError
|
If user_code is already authorized/denied |
Source code in campus_python/auth/v1/oauth.py
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 | |
revoke(token: str, client_id: str, token_type_hint: str | None = None) -> None
¶
Revoke an access or refresh token (RFC 7009).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token
|
str
|
The access or refresh token to revoke |
required |
client_id
|
str
|
The OAuth client the token was issued to |
required |
token_type_hint
|
str | None
|
Optional "access_token" or "refresh_token" |
None
|
Per RFC 7009 section 2.2 the server returns 200 regardless of whether the token was found or already revoked, so callers cannot use this endpoint to confirm a token's validity.
Source code in campus_python/auth/v1/oauth.py
287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | |
LoginSessions¶
campus_python.auth.v1.logins.LoginSessions
¶
Bases: ResourceCollection
Campus Auth Logins resource.
Source code in campus_python/auth/v1/logins.py
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | |
path = 'logins'
class-attribute
instance-attribute
¶
Login
¶
Bases: Resource
A single login session resource.
Source code in campus_python/auth/v1/logins.py
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | |
session_id: str
property
¶
The login session id embedded in this resource's path.
revoke() -> None
¶
Revoke this login session (log the user out).
Source code in campus_python/auth/v1/logins.py
118 119 120 | |
get() -> campus.model.LoginSession
¶
Get this login session.
Returns:
| Type | Description |
|---|---|
LoginSession
|
The LoginSession. |
Source code in campus_python/auth/v1/logins.py
122 123 124 125 126 127 128 129 | |
update(*, expiry_seconds: int) -> campus.model.LoginSession
¶
Extend or shorten this login session.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
expiry_seconds
|
int
|
New session lifetime in seconds. |
required |
Returns:
| Type | Description |
|---|---|
LoginSession
|
The updated LoginSession. |
Source code in campus_python/auth/v1/logins.py
131 132 133 134 135 136 137 138 139 140 141 142 143 144 | |
token() -> campus.model.OAuthToken
¶
Re-acquire the session user's campus bearer (#117).
POST /logins/
The call presents Basic client credentials, never the ambient bearer: the route denies user principals outright (#963/A10), and with_user_session() nested inside another with_user_session() (e.g. an auth-broker release reached from a route that already holds the user session) would otherwise present the outer session's user token and be refused with 403. Any prior Authorization header is restored afterwards, so an enclosing session keeps its authorization until it re-runs use_token() with the fresh bearer.
Source code in campus_python/auth/v1/logins.py
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | |
__getitem__(session_id: str | None = None) -> LoginSessions.Login
¶
Get a login session resource by ID.
Without an explicit ID, the id resolves from the installed session-id provider. There is no framework fallback: hosts without a provider must pass the id explicitly.
Source code in campus_python/auth/v1/logins.py
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | |
from_session(session_id: str | None = None) -> campus.model.LoginSession
¶
Get a login session using a client-side session ID.
Resolution order: explicit session_id > the installed session-id provider. There is no framework fallback.
Source code in campus_python/auth/v1/logins.py
51 52 53 54 55 56 57 58 59 60 | |
has_session() -> bool
¶
True when the installed session-id provider supplies a login id for this lane.
Source code in campus_python/auth/v1/logins.py
62 63 64 65 | |
token(session_id: str | None = None) -> campus.model.OAuthToken
¶
Re-acquire the current login session's campus bearer (#117).
One endpoint call (campus#964, invariant A10):
POST /logins/
The session id resolves explicitly > installed provider.
Raises:
| Type | Description |
|---|---|
AuthenticationError
|
If no login session is present. |
APIError
|
invalid_grant when the session or the user's campus grant is gone — the cue to require re-login. |
Source code in campus_python/auth/v1/logins.py
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | |
new(*, user_id: str, device_id: str | None = None, agent_string: str) -> campus.model.LoginSession
¶
Create a new login session.
Mirrors the payload expected by the logins routes. Storing the returned session's id client-side is the host's business (flask_campus context owns its flask.session storage).
Source code in campus_python/auth/v1/logins.py
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | |
CampusSessions¶
campus_python.auth.v1.sessions.CampusSessions
¶
Bases: ResourceCollection
Campus Auth Sessions resource.
Source code in campus_python/auth/v1/sessions.py
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | |
path = f'sessions/{PROVIDER}'
class-attribute
instance-attribute
¶
Session
¶
Bases: Resource
A single provider session (/sessions/campus/{session_id}).
Source code in campus_python/auth/v1/sessions.py
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | |
session_id: str
property
¶
The auth session id embedded in this resource's path.
finalize() -> tuple[str, campus.model.User | None]
¶
Finalize this session (post-authorization).
Returns:
| Type | Description |
|---|---|
(target_url, user_or_None)
|
where to redirect the |
User | None
|
browser, plus the session user when the calling client |
tuple[str, User | None]
|
owns the session; None from pre-#879 services. |
Source code in campus_python/auth/v1/sessions.py
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 | |
get() -> campus.model.AuthSession
¶
Get this auth session.
Returns:
| Type | Description |
|---|---|
AuthSession
|
The AuthSession. |
Source code in campus_python/auth/v1/sessions.py
188 189 190 191 192 193 194 195 | |
update(**updates) -> None
¶
Update this auth session.
Only user_id and authorization_code are expected by the API; keyword arguments map to session fields.
Source code in campus_python/auth/v1/sessions.py
197 198 199 200 201 202 203 204 205 | |
__getitem__(session_id: str) -> CampusSessions.Session
¶
Source code in campus_python/auth/v1/sessions.py
29 30 | |
from_code(code: str) -> campus.model.AuthSession
¶
Get a session using authorization code.
Source code in campus_python/auth/v1/sessions.py
32 33 34 35 36 37 | |
from_session(session_id: str | None = None) -> campus.model.AuthSession
¶
Get a session by its client-side session id.
Resolution order: explicit session_id > the installed session-id provider. There is no framework fallback: hosts without a provider must pass the id explicitly.
Source code in campus_python/auth/v1/sessions.py
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | |
has_session() -> bool
¶
True when the installed session-id provider supplies a session id for this lane.
Source code in campus_python/auth/v1/sessions.py
60 61 62 63 | |
new(*, user_id: str | None = None, redirect_uri: str, scopes: list[str], target: str | None = None) -> campus.model.AuthSession
¶
Create a new auth session (start the OAuth authorize flow).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
str | None
|
Optional user to pre-authorize. |
None
|
redirect_uri
|
str
|
OAuth redirect URI. |
required |
scopes
|
list[str]
|
Scopes to request. |
required |
target
|
str | None
|
Where to redirect after authorize. |
None
|
Returns:
| Type | Description |
|---|---|
AuthSession
|
The created AuthSession. |
Source code in campus_python/auth/v1/sessions.py
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | |
list(*, provider: str | None = PROVIDER, client_id: str | None = None, user_id: str | None = None, limit: int | None = None, offset: int | None = None) -> list[campus.model.AuthSession]
¶
List live sessions (admin view, campus#1055).
GET /sessions/ with optional provider/client_id/user_id filters and limit/offset pagination. Requires the operator principal or a designated admin user (sessions:read); client principals are denied. Records carry metadata only — no authorization_code, no user embeds — and finalized sessions are absent (finalize deletes the record).
Source code in campus_python/auth/v1/sessions.py
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | |
sweep(at_time: datetime | str | None = None) -> int
¶
Finalize expired auth sessions.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
at_time
|
datetime | str | None
|
Cutoff time (defaults to now, UTC). |
None
|
Returns:
| Type | Description |
|---|---|
int
|
Number of sessions swept. |
Source code in campus_python/auth/v1/sessions.py
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 | |
Clients¶
campus_python.auth.v1.clients.Clients
¶
Bases: ResourceCollection
Campus Auth Clients resource.
Source code in campus_python/auth/v1/clients.py
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | |
path = 'clients'
class-attribute
instance-attribute
¶
Client
¶
Bases: Resource
Campus Auth Client resource.
Source code in campus_python/auth/v1/clients.py
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | |
access: 'Clients.Client.ClientAccess'
property
¶
client_id: str
property
¶
The client_id of the resource was passed in as a path parameter, and is extracted using this property alias.
ClientAccess
¶
Bases: Resource
Campus Auth Client Access resource.
Source code in campus_python/auth/v1/clients.py
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | |
get(vault: str | None = None) -> JsonDict
¶
Get this client's vault access mapping.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault
|
str | None
|
Scope the mapping to one vault label. |
None
|
Returns:
| Type | Description |
|---|---|
JsonDict
|
{vault_label: permission} for the accessible vaults. |
Source code in campus_python/auth/v1/clients.py
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | |
check(vault: str, permission: int) -> JsonDict
¶
Check whether the client holds a permission on a vault.
GET /
Source code in campus_python/auth/v1/clients.py
172 173 174 175 176 177 178 179 180 181 182 183 184 185 | |
grant(vault: str, permission: int) -> JsonDict
¶
Grant this client a permission on a vault.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault
|
str
|
Vault label. |
required |
permission
|
int
|
Permission level to grant. |
required |
Returns:
| Type | Description |
|---|---|
JsonDict
|
The resulting access record. |
Source code in campus_python/auth/v1/clients.py
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | |
revoke(vault: str, permission: int) -> JsonDict
¶
Revoke this client's permission on a vault.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault
|
str
|
Vault label. |
required |
permission
|
int
|
Permission level to revoke. |
required |
Returns:
| Type | Description |
|---|---|
JsonDict
|
The resulting access record. |
Source code in campus_python/auth/v1/clients.py
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | |
update(vault: str, permission: int) -> JsonDict
¶
Set this client's permission on a vault (upsert).
PATCHes the access collection directly.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
vault
|
str
|
Vault label. |
required |
permission
|
int
|
Permission level to set. |
required |
Returns:
| Type | Description |
|---|---|
JsonDict
|
The resulting access record. |
Source code in campus_python/auth/v1/clients.py
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | |
delete() -> None
¶
Delete this client.
Source code in campus_python/auth/v1/clients.py
86 87 88 | |
get() -> campus.model.Client
¶
Get this client.
Returns:
| Type | Description |
|---|---|
Client
|
The Client. |
Source code in campus_python/auth/v1/clients.py
90 91 92 93 94 95 96 97 | |
revoke() -> str
¶
Revoke the client secret and return the new one.
Returns:
| Type | Description |
|---|---|
str
|
The newly generated client secret. |
Source code in campus_python/auth/v1/clients.py
99 100 101 102 103 104 105 | |
update(name: str | None = None, description: str | None = None, redirect_uris: list[str] | None = None, allowed_scopes: list[str] | None = None, upstream_scopes: dict[str, list[str]] | None = None, token_bridge: bool | None = None) -> campus.model.Client
¶
Update the client.
Only the fields passed are sent; the server replaces each provided field wholesale (PATCH semantics), so list and dict values must carry the full desired contents.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str | None
|
New client name |
None
|
description
|
str | None
|
New client description |
None
|
redirect_uris
|
list[str] | None
|
New OAuth redirect URIs |
None
|
allowed_scopes
|
list[str] | None
|
Replacement token-scope allowlist (fail-closed: an empty list grants nothing) |
None
|
upstream_scopes
|
dict[str, list[str]] | None
|
Replacement per-provider upstream scope map (e.g. {"google": [...]}) |
None
|
token_bridge
|
bool | None
|
Token bridge access flag (rejected by the server for public clients) |
None
|
Returns:
| Type | Description |
|---|---|
Client
|
The updated Client |
Source code in campus_python/auth/v1/clients.py
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 | |
__getitem__(client_id: str) -> 'Clients.Client'
¶
Get a specific client resource by ID.
Source code in campus_python/auth/v1/clients.py
16 17 18 | |
list() -> 'list[campus.model.Client]'
¶
List all OAuth clients.
Returns:
| Type | Description |
|---|---|
'list[campus.model.Client]'
|
List of Client objects. |
Source code in campus_python/auth/v1/clients.py
20 21 22 23 24 25 26 27 28 29 30 | |
new(name: str, description: str, is_public: bool = False, redirect_uris: list[str] | None = None, allowed_scopes: list[str] | None = None, upstream_scopes: dict[str, list[str]] | None = None, token_bridge: bool | None = None) -> campus.model.Client
¶
Create a new client.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Client name |
required |
description
|
str
|
Client description |
required |
is_public
|
bool
|
True for public clients (CLI/mobile apps) without secrets |
False
|
redirect_uris
|
list[str] | None
|
OAuth redirect URIs for public clients |
None
|
allowed_scopes
|
list[str] | None
|
Token-scope allowlist (fail-closed: an empty list grants nothing) |
None
|
upstream_scopes
|
dict[str, list[str]] | None
|
Per-provider upstream scope map (e.g. {"google": [...]}) |
None
|
token_bridge
|
bool | None
|
Token bridge access flag (upstream token release; rejected by the server for public clients) |
None
|
Returns:
| Type | Description |
|---|---|
Client
|
The created Client |
Source code in campus_python/auth/v1/clients.py
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | |
Credentials¶
campus_python.auth.v1.credentials.Credentials
¶
Bases: ResourceCollection
Campus Auth Credentials resource.
Usage:
- creds = Credentials(root=...)
- creds["github"].get(token_id) -> get by token id
- creds["github"][user_id].get(client_id) -> get credentials for user
Source code in campus_python/auth/v1/credentials.py
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | |
path = 'credentials'
class-attribute
instance-attribute
¶
Provider
¶
Bases: Resource
Provider-level credentials resource.
Instance path is set to include the provider name so that
requests are made to /{base}/{credentials}/{provider}.
Source code in campus_python/auth/v1/credentials.py
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | |
User
¶
Bases: Resource
Credentials for a single user under a provider.
Source code in campus_python/auth/v1/credentials.py
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | |
delete(client_id: str | None = None) -> None
¶
Disconnect this user's credential record.
Deletes the calling client's record by default; campus#1055 opens the body client_id to the operator so a deployment admin can disconnect an arbitrary integration's stored record for (provider, user).
Source code in campus_python/auth/v1/credentials.py
76 77 78 79 80 81 82 83 84 85 86 87 88 | |
get(include_token: bool = False) -> campus.model.UserCredentials
¶
Get this user's credential record (redacted by default; include_token opts into the raw token, campus#1055).
Source code in campus_python/auth/v1/credentials.py
90 91 92 93 94 95 96 97 98 99 100 | |
new(scopes: list[str], expires_in: int) -> campus.model.UserCredentials
¶
Issue new credentials for this provider and user.
POST /credentials/
Returns:
| Type | Description |
|---|---|
UserCredentials
|
The created UserCredentials |
Source code in campus_python/auth/v1/credentials.py
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 | |
update(token: campus.model.OAuthToken) -> None
¶
Replace this user's stored token for the provider.
The client_id rides on the body from the environment; the token is sent as its full resource form.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
token
|
OAuthToken
|
The new OAuthToken to store. |
required |
Source code in campus_python/auth/v1/credentials.py
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | |
__getitem__(user_id: str) -> Credentials.Provider.User
¶
Get a user-specific credential resource.
Source code in campus_python/auth/v1/credentials.py
37 38 39 | |
get(token_id: str, include_token: bool = False) -> campus.model.UserCredentials
¶
Get one credential record.
Reads are redacted by default (campus#1055): the joined token carries metadata only. include_token=True opts into the raw token — an operator-principal power on the service, honored on per-record reads only.
Source code in campus_python/auth/v1/credentials.py
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | |
list() -> list[campus.model.UserCredentials]
¶
List credential records (admin view, campus#1055).
Records carry token metadata only: the service never releases raw tokens in bulk, include opt-ins are honored on per-record reads exclusively.
Source code in campus_python/auth/v1/credentials.py
60 61 62 63 64 65 66 67 68 69 70 71 | |
__getitem__(provider: str) -> Credentials.Provider
¶
Get provider-level collection.
Source code in campus_python/auth/v1/credentials.py
26 27 28 | |
Users¶
campus_python.auth.v1.users.Users
¶
Bases: ResourceCollection
Vault Users resource.
Source code in campus_python/auth/v1/users.py
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | |
path = 'users'
class-attribute
instance-attribute
¶
User
¶
Bases: Resource
Single vault user resource.
Source code in campus_python/auth/v1/users.py
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | |
activate() -> campus.model.User
¶
Activate this user (allows login).
Returns:
| Type | Description |
|---|---|
User
|
The activated User. |
Source code in campus_python/auth/v1/users.py
55 56 57 58 59 60 61 62 63 | |
delete() -> None
¶
Delete this user.
Source code in campus_python/auth/v1/users.py
65 66 67 | |
get() -> campus.model.User
¶
Get this user.
Returns:
| Type | Description |
|---|---|
User
|
The User. |
Source code in campus_python/auth/v1/users.py
69 70 71 72 73 74 75 76 | |
update(*, name: str) -> campus.model.User
¶
Update the user's display name (campus-cli#42).
The server PATCH accepts name only: a user's id IS its email (identity), and activation runs through the /activate endpoint, so no other field is patchable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
New display name |
required |
Returns:
| Type | Description |
|---|---|
User
|
The updated User |
Source code in campus_python/auth/v1/users.py
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | |
__getitem__(user_id: str) -> Users.User
¶
Get a specific user resource by ID.
Source code in campus_python/auth/v1/users.py
19 20 21 | |
list() -> list[campus.model.User]
¶
List all users.
Returns:
| Type | Description |
|---|---|
list[User]
|
List of User objects. |
Source code in campus_python/auth/v1/users.py
23 24 25 26 27 28 29 30 31 32 33 | |
new(*, email: str, name: str) -> campus.model.User
¶
Create a user.
A user's id IS its email.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
email
|
str
|
The user's email (also their id). |
required |
name
|
str
|
Display name. |
required |
Returns:
| Type | Description |
|---|---|
User
|
The created User. |
Source code in campus_python/auth/v1/users.py
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | |
Vaults¶
Vault values are addressed mapping-style: vaults["mylabel"]["key"],
vaults["mylabel"]["key"] = value, del vaults["mylabel"]["key"];
missing keys raise KeyError.
campus_python.auth.v1.vaults.Vaults
¶
Bases: ResourceCollection
Campus Auth Vaults resource.
Source code in campus_python/auth/v1/vaults.py
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | |
path = 'vaults'
class-attribute
instance-attribute
¶
Vault
¶
Bases: Resource
A single vault (label) exposing mapping-like access.
Source code in campus_python/auth/v1/vaults.py
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | |
keys() -> list[str]
¶
List the keys stored in this vault.
Source code in campus_python/auth/v1/vaults.py
36 37 38 39 | |
__delitem__(key: str) -> None
¶
Source code in campus_python/auth/v1/vaults.py
41 42 43 44 45 46 | |
__getitem__(key: str) -> str
¶
Source code in campus_python/auth/v1/vaults.py
48 49 50 51 52 53 54 55 56 | |
__setitem__(key: str, value: Any) -> None
¶
Source code in campus_python/auth/v1/vaults.py
58 59 60 | |
__getitem__(label: str) -> Vaults.Vault
¶
Source code in campus_python/auth/v1/vaults.py
20 21 | |
labels() -> list[str]
¶
List vault labels (admin view, campus#1055).
GET /vaults/ — the operator, the super-admin root, or designated users holding any vault grant row plus the vaults:read scope; client principals hold per-label access only and cannot enumerate.
Source code in campus_python/auth/v1/vaults.py
23 24 25 26 27 28 29 30 31 | |
Grants¶
The access-grant store: who can administer which vocabulary, and vault bitflag access.
campus_python.auth.v1.grants.Grants
¶
Bases: ResourceCollection
Campus Auth access-grant store.
Source code in campus_python/auth/v1/grants.py
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | |
path = 'grants'
class-attribute
instance-attribute
¶
list(*, grantee_type: str | None = None, grantee_id: str | None = None, resource_type: str | None = None, resource_id: str | None = None) -> JsonDict
¶
List access-grant rows.
Authorization: unfiltered lists require the operator; user principals may list only the single vocabulary they administer.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
grantee_type
|
str | None
|
Filter by "user" or "client" |
None
|
grantee_id
|
str | None
|
Filter by grantee identity (user email / client id) |
None
|
resource_type
|
str | None
|
Filter by vocabulary ("users", "clients", "vault", ...) |
None
|
resource_id
|
str | None
|
Filter by instance (vault label) |
None
|
Returns:
| Type | Description |
|---|---|
JsonDict
|
{"grants": [...]} |
Source code in campus_python/auth/v1/grants.py
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | |
check(*, grantee_type: str, grantee_id: str, resource_type: str, resource_id: str = '', bits: int | None = None, level: str | None = None) -> bool
¶
Check whether a grantee's row covers a permission.
Authorization: operator, or a same-vocabulary admin.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
grantee_type
|
str
|
"user" or "client" |
required |
grantee_id
|
str
|
Grantee identity |
required |
resource_type
|
str
|
Vocabulary ("users", "clients", "vault", ...) |
required |
resource_id
|
str
|
Instance (vault label; default none) |
''
|
bits
|
int | None
|
Vault bitflag mask to test |
None
|
level
|
str | None
|
Management level to test |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
True when the held row covers the requested permission |
Source code in campus_python/auth/v1/grants.py
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | |
grant(*, grantee_type: str, grantee_id: str, resource_type: str, resource_id: str = '', bits: int | None = None, level: str | None = None) -> JsonDict
¶
Grant access (create a row, or raise an existing one).
Authorization: operator, or a same-vocabulary admin. Vault bits OR into the existing mask; management levels never downgrade — revoke first to lower a level.
Anti-escalation (#883): no principal may administer its own grants, and vocabulary-level clients:admin rows are rejected (operator-equivalent).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
grantee_type
|
str
|
"user" or "client" |
required |
grantee_id
|
str
|
Grantee identity |
required |
resource_type
|
str
|
Vocabulary ("users", "clients", "vault", ...) |
required |
resource_id
|
str
|
Instance (required for vault labels) |
''
|
bits
|
int | None
|
Vault bitflag mask (vaults only) |
None
|
level
|
str | None
|
Management level (read/mod/write/admin) |
None
|
Returns:
| Type | Description |
|---|---|
JsonDict
|
The grant row (post-application state) |
Source code in campus_python/auth/v1/grants.py
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | |
revoke(*, grantee_type: str, grantee_id: str, resource_type: str, resource_id: str = '', bits: int | None = None, level: str | None = None) -> JsonDict | None
¶
Revoke access (clear vault bits, delete covered levels).
Authorization: operator, or a same-vocabulary admin. Vault rows delete at zero bits; a revoked level's row is deleted when the held level covers it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
grantee_type
|
str
|
"user" or "client" |
required |
grantee_id
|
str
|
Grantee identity |
required |
resource_type
|
str
|
Vocabulary |
required |
resource_id
|
str
|
Instance (vault label) |
''
|
bits
|
int | None
|
Vault bitflag mask to clear |
None
|
level
|
str | None
|
Management level to revoke |
None
|
Returns:
| Type | Description |
|---|---|
JsonDict | None
|
The remaining grant row, or None when the row was deleted |
Source code in campus_python/auth/v1/grants.py
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 | |
delete(grant_id: str) -> None
¶
Delete a grant row outright by its id.
Authorization: operator, or a same-vocabulary admin for the row's vocabulary.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
grant_id
|
str
|
The grant row's id (from list()) |
required |
Source code in campus_python/auth/v1/grants.py
179 180 181 182 183 184 185 186 187 188 | |
Connections¶
The user-facing view of upstream provider connections (metadata only — token values are broker-only).
campus_python.auth.v1.connections.Connections
¶
Bases: ResourceCollection
Campus Auth Connections resource.
Source code in campus_python/auth/v1/connections.py
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | |
path = 'connections'
class-attribute
instance-attribute
¶
Connection
¶
Bases: Resource
Single provider connection resource.
Source code in campus_python/auth/v1/connections.py
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | |
Integration
¶
Bases: Resource
Integration-namespaced connection resource.
Source code in campus_python/auth/v1/connections.py
69 70 71 72 73 74 75 76 77 78 79 80 | |
delete(*, user_id: str | None = None) -> None
¶
Disconnect this provider integration (e.g. google/classroom).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
str | None
|
Delegated target user (required for basic auth) |
None
|
Source code in campus_python/auth/v1/connections.py
72 73 74 75 76 77 78 79 80 | |
__getitem__(integration: str) -> Connections.Connection.Integration
¶
Get an integration-namespaced connection resource.
Source code in campus_python/auth/v1/connections.py
47 48 49 50 51 52 53 54 | |
delete(*, user_id: str | None = None) -> None
¶
Disconnect every credential for this base provider.
404 (NotFoundError) means there was nothing to disconnect; callers treating disconnect as idempotent can catch it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
str | None
|
Delegated target user (required for basic auth) |
None
|
Source code in campus_python/auth/v1/connections.py
56 57 58 59 60 61 62 63 64 65 66 67 | |
__getitem__(provider: str) -> Connections.Connection
¶
Get a specific provider's connection resource.
Source code in campus_python/auth/v1/connections.py
19 20 21 | |
list(*, user_id: str | None = None) -> list[JsonDict]
¶
List the target user's upstream connections.
Each entry carries {provider, integration, scopes, connected_at, expires_at} — never token values. Auth shape mirrors the server: a bearer token acts for its own user (user_id ignored), while basic (client-credentials) auth must name a user via user_id.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
user_id
|
str | None
|
Delegated target user (required for basic auth) |
None
|
Returns:
| Type | Description |
|---|---|
list[JsonDict]
|
List of connection metadata dicts |
Source code in campus_python/auth/v1/connections.py
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | |
Broker¶
The sanctioned release path for upstream access tokens
(token_bridge clients).
campus_python.auth.v1.broker.Broker
¶
Bases: ResourceRoot
Campus Auth token broker resource.
Source code in campus_python/auth/v1/broker.py
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | |
url_prefix = '/auth/v1/broker'
class-attribute
instance-attribute
¶
__init__(root: ResourceRoot)
¶
Source code in campus_python/auth/v1/broker.py
22 23 24 | |
token(provider: str, integration: str | None = None, *, min_scopes: list[str] | None = None) -> JsonDict
¶
Release the bearer's upstream access token for a provider.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
provider
|
str
|
Base provider (e.g. "google") |
required |
integration
|
str | None
|
Integration slug for the namespaced route (e.g. "classroom" → /broker/google/classroom/) |
None
|
min_scopes
|
list[str] | None
|
Scopes the caller requires; denied unless the user's upstream grant covers them and the client's upstream_scopes allowlist permits them |
None
|
Returns:
| Type | Description |
|---|---|
JsonDict
|
{provider, user_id, access_token, token_type, expires_in, |
JsonDict
|
scope} — the refresh token never leaves Campus |
Raises:
| Type | Description |
|---|---|
NotFoundError
|
No connection for this provider (404); namespaced providers pointed at the identity route are redirected to the integration route the same way |
AuthenticationError
|
Bearer session expired (401) |
APIError
|
403 with details.missing_scopes, or 400 AUTH_INVALID_SCOPE / configuration problems |
Source code in campus_python/auth/v1/broker.py
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | |
Root¶
Operator-facing root actions (token/client introspection).
campus_python.auth.v1.root.Root
¶
Bases: ResourceCollection
Campus Auth root resource.
Source code in campus_python/auth/v1/root.py
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | |
path = 'root'
class-attribute
instance-attribute
¶
authenticate(*, token: str | None = None, client_id: schema.CampusID | None = None, client_secret: str | None = None) -> dict[str, Any]
¶
Authenticate the given token or client credentials.
{
| Type | Description |
|---|---|
dict[str, Any]
|
"client": { ... } |
} or { "client": { ... }, "user": { ... } }
Source code in campus_python/auth/v1/root.py
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | |
Session-id seam¶
The session-id resolver flask_campus installs; ids resolve explicit argument > provider.
campus_python.auth.v1.sessionstore
¶
campus.python.auth.v1.sessionstore
Client-side session-id resolution seam for the auth session/login lanes.
The SDK never touches a web-framework session store: hosts that keep their session ids in their own request state — e.g. flask_campus, which stores them under sessions.SESSION_STORAGE_KEY / logins.LOGIN_STORAGE_KEY — install a provider that resolves the current id per lane:
from campus_python.auth import v1
v1.set_session_id_provider(my_resolver)
The provider takes a lane name — "session" for auth sessions or "login" for login sessions — and returns the current session id or None. Every read resolves explicit argument first, then the provider; with neither, the resource methods raise AuthenticationError naming the seam to install.
set_session_id_provider(provider: typing.Callable[[str], str | None] | None) -> None
¶
Install (or clear) the session-id resolver for both lanes.
The provider is consulted whenever a resource method needs the current session id and none was passed explicitly. Pass None to clear it (tests).
Source code in campus_python/auth/v1/sessionstore.py
36 37 38 39 40 41 42 43 44 45 46 | |