sg-token-broker 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sg_token_broker-0.1.0/.gitignore +46 -0
- sg_token_broker-0.1.0/LICENSE +21 -0
- sg_token_broker-0.1.0/PKG-INFO +208 -0
- sg_token_broker-0.1.0/README.md +176 -0
- sg_token_broker-0.1.0/pyproject.toml +171 -0
- sg_token_broker-0.1.0/src/sg_token_broker/__init__.py +33 -0
- sg_token_broker-0.1.0/src/sg_token_broker/__main__.py +8 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_audit.py +33 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_cache.py +189 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_cli.py +711 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_client.py +254 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_config.py +299 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_credstore.py +177 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_downstream.py +143 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_gclaims.py +174 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_googleverify.py +61 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_http.py +329 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_httpbase.py +211 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_oidcverify.py +258 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_secrets.py +148 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_service.py +363 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_sg.py +285 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_urlpolicy.py +54 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_userauth.py +687 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_userclient.py +270 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_userconfig.py +219 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_userhttp.py +208 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_users.py +147 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_usertoken.py +449 -0
- sg_token_broker-0.1.0/src/sg_token_broker/_verify.py +236 -0
- sg_token_broker-0.1.0/src/sg_token_broker/py.typed +0 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
dist/
|
|
13
|
+
.eggs/
|
|
14
|
+
*.egg-info/
|
|
15
|
+
*.egg
|
|
16
|
+
|
|
17
|
+
# Virtual environments
|
|
18
|
+
.venv/
|
|
19
|
+
venv/
|
|
20
|
+
ENV/
|
|
21
|
+
|
|
22
|
+
# PyInstaller
|
|
23
|
+
*.manifest
|
|
24
|
+
*.spec
|
|
25
|
+
|
|
26
|
+
# Unit test / coverage reports
|
|
27
|
+
htmlcov/
|
|
28
|
+
.tox/
|
|
29
|
+
.nox/
|
|
30
|
+
.coverage*
|
|
31
|
+
.pytest_cache/
|
|
32
|
+
.cache/
|
|
33
|
+
|
|
34
|
+
# Type checker / linter caches
|
|
35
|
+
.pyright/
|
|
36
|
+
.mypy_cache/
|
|
37
|
+
.ruff_cache/
|
|
38
|
+
pyrightconfig.json
|
|
39
|
+
|
|
40
|
+
# Editors
|
|
41
|
+
.vscode/
|
|
42
|
+
.idea/
|
|
43
|
+
|
|
44
|
+
# OS
|
|
45
|
+
.DS_Store
|
|
46
|
+
Thumbs.db
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 the sg-token-broker authors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: sg-token-broker
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Authentication broker for Autodesk Flow Production Tracking
|
|
5
|
+
Project-URL: Documentation, https://github.com/dactylo/sg-token-broker/tree/main/docs
|
|
6
|
+
Project-URL: Homepage, https://github.com/dactylo/sg-token-broker
|
|
7
|
+
Project-URL: Issues, https://github.com/dactylo/sg-token-broker/issues
|
|
8
|
+
Project-URL: Repository, https://github.com/dactylo/sg-token-broker
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: authentication,credentials,flow-production-tracking,security,shotgrid,shotgun,token-broker
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
18
|
+
Classifier: Typing :: Typed
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
21
|
+
Requires-Dist: requests>=2.34.2
|
|
22
|
+
Requires-Dist: urllib3<3,>=1.26
|
|
23
|
+
Provides-Extra: google
|
|
24
|
+
Requires-Dist: cachecontrol>=0.14.4; extra == 'google'
|
|
25
|
+
Requires-Dist: google-auth>=2.3.2; extra == 'google'
|
|
26
|
+
Provides-Extra: login
|
|
27
|
+
Requires-Dist: keyring>=24; extra == 'login'
|
|
28
|
+
Provides-Extra: oidc
|
|
29
|
+
Requires-Dist: cryptography>=42; extra == 'oidc'
|
|
30
|
+
Requires-Dist: pyjwt<2.16,>=2.14; extra == 'oidc'
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# sg-token-broker
|
|
34
|
+
|
|
35
|
+
sg-token-broker lets pipeline tools call Autodesk Flow Production Tracking without receiving
|
|
36
|
+
long-lived API script keys. A service you run keeps the keys, checks each caller, and issues an SG
|
|
37
|
+
token with the permissions of a configured script account or of the signed-in person.
|
|
38
|
+
|
|
39
|
+
Use it when farm jobs, pipeline services, desktop tools, or Google Sheets need SG access and you
|
|
40
|
+
want to keep script keys on one host, limit which SG identities each caller can use, and record
|
|
41
|
+
every issuance in an audit log.
|
|
42
|
+
|
|
43
|
+
This documentation uses SG for Flow Production Tracking, formerly named Shotgun and ShotGrid.
|
|
44
|
+
|
|
45
|
+
## Choose a service
|
|
46
|
+
|
|
47
|
+
Choose by whose permissions SG should enforce:
|
|
48
|
+
|
|
49
|
+
- **App-token broker:** for farm jobs, pipeline services, and shared tools. Each named *scope* maps
|
|
50
|
+
to an SG script account with a limited permission role, and each consuming system gets its own
|
|
51
|
+
broker credential.
|
|
52
|
+
- **User-token service:** for tools that act as the signed-in person. The service verifies the
|
|
53
|
+
person's studio sign-in and issues a token bound to their own SG account.
|
|
54
|
+
|
|
55
|
+
Both services issue REST tokens and session tokens. Existing `shotgun_api3` integrations need
|
|
56
|
+
session tokens, and user session tokens require a private deployment on a restricted network. See
|
|
57
|
+
[Choosing a credential](https://github.com/dactylo/sg-token-broker/blob/v0.1.0/docs/modes.md) for the tradeoffs.
|
|
58
|
+
|
|
59
|
+
## Installation
|
|
60
|
+
|
|
61
|
+
You need Python 3.11 or later and [uv](https://docs.astral.sh/uv/). Running either service also
|
|
62
|
+
requires an SG site and an SG administrator who can create script accounts.
|
|
63
|
+
|
|
64
|
+
From a checkout of this repository, install the `sg-token-broker` command:
|
|
65
|
+
|
|
66
|
+
```sh
|
|
67
|
+
uv tool install .
|
|
68
|
+
sg-token-broker --help
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
After pulling changes, update it with `uv tool install --reinstall .`. The app-token broker and its
|
|
72
|
+
clients need no extras. Add an extra, as in `uv tool install '.[login]'`, for these features:
|
|
73
|
+
|
|
74
|
+
- `login`: stores a desktop sign-in in the operating system's keyring, so later commands do not
|
|
75
|
+
open a browser.
|
|
76
|
+
- `google`: lets the user-token service verify Google Workspace ID tokens.
|
|
77
|
+
- `oidc`: lets the user-token service verify ID tokens from another OIDC provider.
|
|
78
|
+
|
|
79
|
+
For Python integrations, install the package into the environment that runs your application, for
|
|
80
|
+
example with that environment's `python -m pip install /path/to/sg-token-broker`. The
|
|
81
|
+
`shotgun_api3` examples also need the SG Python API in that environment. A `uv tool` installation
|
|
82
|
+
does not make the library importable from other environments.
|
|
83
|
+
|
|
84
|
+
## Quick start
|
|
85
|
+
|
|
86
|
+
This walkthrough runs the app-token broker on your machine and fetches a token for one scope. First
|
|
87
|
+
ask an SG administrator to create a script account, such as `broker_read_all`, whose permission
|
|
88
|
+
role grants only what your tool needs. Only the broker uses that account's application key.
|
|
89
|
+
|
|
90
|
+
### Create a client credential
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
sg-token-broker hash-secret
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
The command prints a `secret:` line for the consuming tool and a `hash:` line for the broker
|
|
97
|
+
configuration. The broker stores only the hash.
|
|
98
|
+
|
|
99
|
+
### Configure the broker
|
|
100
|
+
|
|
101
|
+
Save this as `broker.yml`, replacing the site URL and `secret_hash` with your values:
|
|
102
|
+
|
|
103
|
+
```yaml
|
|
104
|
+
site_url: https://your-site.shotgrid.autodesk.com
|
|
105
|
+
server:
|
|
106
|
+
bind: 127.0.0.1
|
|
107
|
+
port: 8743
|
|
108
|
+
scopes:
|
|
109
|
+
read_all:
|
|
110
|
+
script_name: broker_read_all
|
|
111
|
+
script_key_env: SGTB_KEY_READ_ALL
|
|
112
|
+
clients:
|
|
113
|
+
farm_render:
|
|
114
|
+
secret_hash: paste-the-generated-hash-here
|
|
115
|
+
scopes: [read_all]
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The `read_all` scope maps to the `broker_read_all` script account, whose key the broker reads from
|
|
119
|
+
the `SGTB_KEY_READ_ALL` environment variable. The `farm_render` client may request only that scope.
|
|
120
|
+
|
|
121
|
+
### Start the broker
|
|
122
|
+
|
|
123
|
+
Supply the script account's key, validate the configuration, and start the broker:
|
|
124
|
+
|
|
125
|
+
```sh
|
|
126
|
+
export SGTB_KEY_READ_ALL='your-script-application-key'
|
|
127
|
+
sg-token-broker check-config --config broker.yml
|
|
128
|
+
sg-token-broker serve-app-tokens --config broker.yml
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
`check-config` prints `ok: 1 scope(s), 1 client(s)`. The broker then reports
|
|
132
|
+
`serving on http://127.0.0.1:8743` and keeps running. It accepts plain HTTP here only because it
|
|
133
|
+
listens on loopback; any other address requires TLS.
|
|
134
|
+
|
|
135
|
+
### Request a token
|
|
136
|
+
|
|
137
|
+
In another terminal, configure the client and request a token:
|
|
138
|
+
|
|
139
|
+
```sh
|
|
140
|
+
export SG_TOKEN_BROKER_URL='http://127.0.0.1:8743'
|
|
141
|
+
export SG_TOKEN_BROKER_CLIENT_ID='farm_render'
|
|
142
|
+
export SG_TOKEN_BROKER_CLIENT_SECRET='the-generated-client-secret'
|
|
143
|
+
sg-token-broker get-token --scope read_all
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The command prints JSON with the SG session token in `token`, along with `token_type`, `scope`,
|
|
147
|
+
`site_url`, and `expires_at`. Add `--token-type rest` for a REST bearer token. Treat either token
|
|
148
|
+
as a credential. The broker's terminal shows one JSON `issue` record for the request, which
|
|
149
|
+
identifies the token without including it.
|
|
150
|
+
|
|
151
|
+
In Python, with this package and `shotgun_api3` installed in your application's environment:
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
import shotgun_api3
|
|
155
|
+
|
|
156
|
+
from sg_token_broker import BrokerClient
|
|
157
|
+
|
|
158
|
+
token = BrokerClient().fetch_token('read_all')
|
|
159
|
+
sg = shotgun_api3.Shotgun(token.site_url, session_token=token.token)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`BrokerClient` reads the same three environment variables and reuses its token until shortly before
|
|
163
|
+
`expires_at`.
|
|
164
|
+
|
|
165
|
+
This setup listens only on your machine. Before shared use, follow the
|
|
166
|
+
[app-token broker deployment](https://github.com/dactylo/sg-token-broker/blob/v0.1.0/docs/deployment.md) guide for TLS, secret storage, and operations.
|
|
167
|
+
Session tokens stay valid while in use, and rotating a script key does not revoke them; read
|
|
168
|
+
[token lifetime and revocation](https://github.com/dactylo/sg-token-broker/blob/v0.1.0/docs/sg-token-behavior.md) before deploying.
|
|
169
|
+
|
|
170
|
+
## Use the signed-in person's permissions
|
|
171
|
+
|
|
172
|
+
Deploy the [user-token service](https://github.com/dactylo/sg-token-broker/blob/v0.1.0/docs/user-token-service.md) for tools that need the caller's own SG
|
|
173
|
+
permissions. Choose the Cloud Run deployment for Google Workspace callers that use REST, or a
|
|
174
|
+
private deployment for session tokens used by `shotgun_api3`.
|
|
175
|
+
|
|
176
|
+
If your administrator already runs the service, start with
|
|
177
|
+
[desktop client setup](https://github.com/dactylo/sg-token-broker/blob/v0.1.0/docs/user-token-service.md#desktop-client-setup) or the
|
|
178
|
+
[Apps Script caller](https://github.com/dactylo/sg-token-broker/blob/v0.1.0/docs/user-token-service.md#apps-script-caller).
|
|
179
|
+
|
|
180
|
+
## Documentation
|
|
181
|
+
|
|
182
|
+
| If you want to... | Read |
|
|
183
|
+
| ---------------------------------------------------------------- | --------------------------------------------------------------- |
|
|
184
|
+
| Choose between app and user tokens, or session and REST tokens | [Choosing a credential](https://github.com/dactylo/sg-token-broker/blob/v0.1.0/docs/modes.md) |
|
|
185
|
+
| Deploy, operate, or troubleshoot the app-token broker | [App-token broker deployment](https://github.com/dactylo/sg-token-broker/blob/v0.1.0/docs/deployment.md) |
|
|
186
|
+
| Deploy the user-token service | [User-token service](https://github.com/dactylo/sg-token-broker/blob/v0.1.0/docs/user-token-service.md) |
|
|
187
|
+
| Connect a desktop tool or Google Sheet to the user-token service | [Client setup](https://github.com/dactylo/sg-token-broker/blob/v0.1.0/docs/user-token-service.md#desktop-client-setup) |
|
|
188
|
+
| Handle token expiry or respond to a leaked credential | [Token lifetime and revocation](https://github.com/dactylo/sg-token-broker/blob/v0.1.0/docs/sg-token-behavior.md) |
|
|
189
|
+
| Understand the security boundaries and their limits | [Design and security](https://github.com/dactylo/sg-token-broker/blob/v0.1.0/docs/design.md) |
|
|
190
|
+
| See changes by version | [Changelog](https://github.com/dactylo/sg-token-broker/blob/v0.1.0/CHANGELOG.md) |
|
|
191
|
+
|
|
192
|
+
## Development
|
|
193
|
+
|
|
194
|
+
See the [development guide](https://github.com/dactylo/sg-token-broker/blob/v0.1.0/docs/development.md) for the required tools, CI, and dependency locks.
|
|
195
|
+
With those tools installed, run:
|
|
196
|
+
|
|
197
|
+
```sh
|
|
198
|
+
make setup
|
|
199
|
+
make check
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
The checks use a local fake SG server and never contact a live site.
|
|
203
|
+
|
|
204
|
+
## License
|
|
205
|
+
|
|
206
|
+
sg-token-broker is available under the [MIT License](https://github.com/dactylo/sg-token-broker/blob/v0.1.0/LICENSE). It is an independent project and is
|
|
207
|
+
not affiliated with or endorsed by Autodesk. Flow Production Tracking is a product of Autodesk,
|
|
208
|
+
Inc.
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# sg-token-broker
|
|
2
|
+
|
|
3
|
+
sg-token-broker lets pipeline tools call Autodesk Flow Production Tracking without receiving
|
|
4
|
+
long-lived API script keys. A service you run keeps the keys, checks each caller, and issues an SG
|
|
5
|
+
token with the permissions of a configured script account or of the signed-in person.
|
|
6
|
+
|
|
7
|
+
Use it when farm jobs, pipeline services, desktop tools, or Google Sheets need SG access and you
|
|
8
|
+
want to keep script keys on one host, limit which SG identities each caller can use, and record
|
|
9
|
+
every issuance in an audit log.
|
|
10
|
+
|
|
11
|
+
This documentation uses SG for Flow Production Tracking, formerly named Shotgun and ShotGrid.
|
|
12
|
+
|
|
13
|
+
## Choose a service
|
|
14
|
+
|
|
15
|
+
Choose by whose permissions SG should enforce:
|
|
16
|
+
|
|
17
|
+
- **App-token broker:** for farm jobs, pipeline services, and shared tools. Each named *scope* maps
|
|
18
|
+
to an SG script account with a limited permission role, and each consuming system gets its own
|
|
19
|
+
broker credential.
|
|
20
|
+
- **User-token service:** for tools that act as the signed-in person. The service verifies the
|
|
21
|
+
person's studio sign-in and issues a token bound to their own SG account.
|
|
22
|
+
|
|
23
|
+
Both services issue REST tokens and session tokens. Existing `shotgun_api3` integrations need
|
|
24
|
+
session tokens, and user session tokens require a private deployment on a restricted network. See
|
|
25
|
+
[Choosing a credential](docs/modes.md) for the tradeoffs.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
You need Python 3.11 or later and [uv](https://docs.astral.sh/uv/). Running either service also
|
|
30
|
+
requires an SG site and an SG administrator who can create script accounts.
|
|
31
|
+
|
|
32
|
+
From a checkout of this repository, install the `sg-token-broker` command:
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
uv tool install .
|
|
36
|
+
sg-token-broker --help
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
After pulling changes, update it with `uv tool install --reinstall .`. The app-token broker and its
|
|
40
|
+
clients need no extras. Add an extra, as in `uv tool install '.[login]'`, for these features:
|
|
41
|
+
|
|
42
|
+
- `login`: stores a desktop sign-in in the operating system's keyring, so later commands do not
|
|
43
|
+
open a browser.
|
|
44
|
+
- `google`: lets the user-token service verify Google Workspace ID tokens.
|
|
45
|
+
- `oidc`: lets the user-token service verify ID tokens from another OIDC provider.
|
|
46
|
+
|
|
47
|
+
For Python integrations, install the package into the environment that runs your application, for
|
|
48
|
+
example with that environment's `python -m pip install /path/to/sg-token-broker`. The
|
|
49
|
+
`shotgun_api3` examples also need the SG Python API in that environment. A `uv tool` installation
|
|
50
|
+
does not make the library importable from other environments.
|
|
51
|
+
|
|
52
|
+
## Quick start
|
|
53
|
+
|
|
54
|
+
This walkthrough runs the app-token broker on your machine and fetches a token for one scope. First
|
|
55
|
+
ask an SG administrator to create a script account, such as `broker_read_all`, whose permission
|
|
56
|
+
role grants only what your tool needs. Only the broker uses that account's application key.
|
|
57
|
+
|
|
58
|
+
### Create a client credential
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
sg-token-broker hash-secret
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The command prints a `secret:` line for the consuming tool and a `hash:` line for the broker
|
|
65
|
+
configuration. The broker stores only the hash.
|
|
66
|
+
|
|
67
|
+
### Configure the broker
|
|
68
|
+
|
|
69
|
+
Save this as `broker.yml`, replacing the site URL and `secret_hash` with your values:
|
|
70
|
+
|
|
71
|
+
```yaml
|
|
72
|
+
site_url: https://your-site.shotgrid.autodesk.com
|
|
73
|
+
server:
|
|
74
|
+
bind: 127.0.0.1
|
|
75
|
+
port: 8743
|
|
76
|
+
scopes:
|
|
77
|
+
read_all:
|
|
78
|
+
script_name: broker_read_all
|
|
79
|
+
script_key_env: SGTB_KEY_READ_ALL
|
|
80
|
+
clients:
|
|
81
|
+
farm_render:
|
|
82
|
+
secret_hash: paste-the-generated-hash-here
|
|
83
|
+
scopes: [read_all]
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The `read_all` scope maps to the `broker_read_all` script account, whose key the broker reads from
|
|
87
|
+
the `SGTB_KEY_READ_ALL` environment variable. The `farm_render` client may request only that scope.
|
|
88
|
+
|
|
89
|
+
### Start the broker
|
|
90
|
+
|
|
91
|
+
Supply the script account's key, validate the configuration, and start the broker:
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
export SGTB_KEY_READ_ALL='your-script-application-key'
|
|
95
|
+
sg-token-broker check-config --config broker.yml
|
|
96
|
+
sg-token-broker serve-app-tokens --config broker.yml
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`check-config` prints `ok: 1 scope(s), 1 client(s)`. The broker then reports
|
|
100
|
+
`serving on http://127.0.0.1:8743` and keeps running. It accepts plain HTTP here only because it
|
|
101
|
+
listens on loopback; any other address requires TLS.
|
|
102
|
+
|
|
103
|
+
### Request a token
|
|
104
|
+
|
|
105
|
+
In another terminal, configure the client and request a token:
|
|
106
|
+
|
|
107
|
+
```sh
|
|
108
|
+
export SG_TOKEN_BROKER_URL='http://127.0.0.1:8743'
|
|
109
|
+
export SG_TOKEN_BROKER_CLIENT_ID='farm_render'
|
|
110
|
+
export SG_TOKEN_BROKER_CLIENT_SECRET='the-generated-client-secret'
|
|
111
|
+
sg-token-broker get-token --scope read_all
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The command prints JSON with the SG session token in `token`, along with `token_type`, `scope`,
|
|
115
|
+
`site_url`, and `expires_at`. Add `--token-type rest` for a REST bearer token. Treat either token
|
|
116
|
+
as a credential. The broker's terminal shows one JSON `issue` record for the request, which
|
|
117
|
+
identifies the token without including it.
|
|
118
|
+
|
|
119
|
+
In Python, with this package and `shotgun_api3` installed in your application's environment:
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
import shotgun_api3
|
|
123
|
+
|
|
124
|
+
from sg_token_broker import BrokerClient
|
|
125
|
+
|
|
126
|
+
token = BrokerClient().fetch_token('read_all')
|
|
127
|
+
sg = shotgun_api3.Shotgun(token.site_url, session_token=token.token)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`BrokerClient` reads the same three environment variables and reuses its token until shortly before
|
|
131
|
+
`expires_at`.
|
|
132
|
+
|
|
133
|
+
This setup listens only on your machine. Before shared use, follow the
|
|
134
|
+
[app-token broker deployment](docs/deployment.md) guide for TLS, secret storage, and operations.
|
|
135
|
+
Session tokens stay valid while in use, and rotating a script key does not revoke them; read
|
|
136
|
+
[token lifetime and revocation](docs/sg-token-behavior.md) before deploying.
|
|
137
|
+
|
|
138
|
+
## Use the signed-in person's permissions
|
|
139
|
+
|
|
140
|
+
Deploy the [user-token service](docs/user-token-service.md) for tools that need the caller's own SG
|
|
141
|
+
permissions. Choose the Cloud Run deployment for Google Workspace callers that use REST, or a
|
|
142
|
+
private deployment for session tokens used by `shotgun_api3`.
|
|
143
|
+
|
|
144
|
+
If your administrator already runs the service, start with
|
|
145
|
+
[desktop client setup](docs/user-token-service.md#desktop-client-setup) or the
|
|
146
|
+
[Apps Script caller](docs/user-token-service.md#apps-script-caller).
|
|
147
|
+
|
|
148
|
+
## Documentation
|
|
149
|
+
|
|
150
|
+
| If you want to... | Read |
|
|
151
|
+
| ---------------------------------------------------------------- | --------------------------------------------------------------- |
|
|
152
|
+
| Choose between app and user tokens, or session and REST tokens | [Choosing a credential](docs/modes.md) |
|
|
153
|
+
| Deploy, operate, or troubleshoot the app-token broker | [App-token broker deployment](docs/deployment.md) |
|
|
154
|
+
| Deploy the user-token service | [User-token service](docs/user-token-service.md) |
|
|
155
|
+
| Connect a desktop tool or Google Sheet to the user-token service | [Client setup](docs/user-token-service.md#desktop-client-setup) |
|
|
156
|
+
| Handle token expiry or respond to a leaked credential | [Token lifetime and revocation](docs/sg-token-behavior.md) |
|
|
157
|
+
| Understand the security boundaries and their limits | [Design and security](docs/design.md) |
|
|
158
|
+
| See changes by version | [Changelog](CHANGELOG.md) |
|
|
159
|
+
|
|
160
|
+
## Development
|
|
161
|
+
|
|
162
|
+
See the [development guide](docs/development.md) for the required tools, CI, and dependency locks.
|
|
163
|
+
With those tools installed, run:
|
|
164
|
+
|
|
165
|
+
```sh
|
|
166
|
+
make setup
|
|
167
|
+
make check
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The checks use a local fake SG server and never contact a live site.
|
|
171
|
+
|
|
172
|
+
## License
|
|
173
|
+
|
|
174
|
+
sg-token-broker is available under the [MIT License](LICENSE). It is an independent project and is
|
|
175
|
+
not affiliated with or endorsed by Autodesk. Flow Production Tracking is a product of Autodesk,
|
|
176
|
+
Inc.
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
# ==========================================================
|
|
2
|
+
# Build System
|
|
3
|
+
# ==========================================================
|
|
4
|
+
[build-system]
|
|
5
|
+
build-backend = "hatchling.build"
|
|
6
|
+
requires = [ "editables~=0.3", "hatch-fancy-pypi-readme>=25.1", "hatchling>=1.27" ]
|
|
7
|
+
|
|
8
|
+
# ==========================================================
|
|
9
|
+
# Project Metadata
|
|
10
|
+
# ==========================================================
|
|
11
|
+
[project]
|
|
12
|
+
name = "sg-token-broker"
|
|
13
|
+
version = "0.1.0"
|
|
14
|
+
description = "Authentication broker for Autodesk Flow Production Tracking"
|
|
15
|
+
keywords = [
|
|
16
|
+
"authentication",
|
|
17
|
+
"credentials",
|
|
18
|
+
"flow-production-tracking",
|
|
19
|
+
"security",
|
|
20
|
+
"shotgrid",
|
|
21
|
+
"shotgun",
|
|
22
|
+
"token-broker"
|
|
23
|
+
]
|
|
24
|
+
license = "MIT"
|
|
25
|
+
license-files = [ "LICENSE" ]
|
|
26
|
+
requires-python = ">=3.11"
|
|
27
|
+
classifiers = [
|
|
28
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
29
|
+
"Programming Language :: Python :: 3.11",
|
|
30
|
+
"Programming Language :: Python :: 3.12",
|
|
31
|
+
"Programming Language :: Python :: 3.13",
|
|
32
|
+
"Programming Language :: Python :: 3.14",
|
|
33
|
+
"Programming Language :: Python :: 3.15",
|
|
34
|
+
"Typing :: Typed",
|
|
35
|
+
]
|
|
36
|
+
dynamic = [ "readme" ]
|
|
37
|
+
dependencies = [
|
|
38
|
+
"pyyaml>=6.0.3",
|
|
39
|
+
"requests>=2.34.2",
|
|
40
|
+
"urllib3>=1.26,<3",
|
|
41
|
+
]
|
|
42
|
+
optional-dependencies.google = [
|
|
43
|
+
"cachecontrol>=0.14.4",
|
|
44
|
+
"google-auth>=2.3.2",
|
|
45
|
+
]
|
|
46
|
+
optional-dependencies.login = [
|
|
47
|
+
"keyring>=24",
|
|
48
|
+
]
|
|
49
|
+
optional-dependencies.oidc = [
|
|
50
|
+
"cryptography>=42",
|
|
51
|
+
"pyjwt>=2.14,<2.16", # _oidcverify overrides PyJWT internals; widen only after testing
|
|
52
|
+
]
|
|
53
|
+
urls.Documentation = "https://github.com/dactylo/sg-token-broker/tree/main/docs"
|
|
54
|
+
urls.Homepage = "https://github.com/dactylo/sg-token-broker"
|
|
55
|
+
urls.Issues = "https://github.com/dactylo/sg-token-broker/issues"
|
|
56
|
+
urls.Repository = "https://github.com/dactylo/sg-token-broker"
|
|
57
|
+
scripts.sg-token-broker = "sg_token_broker._cli:main"
|
|
58
|
+
|
|
59
|
+
[dependency-groups]
|
|
60
|
+
dev = [
|
|
61
|
+
"mdformat",
|
|
62
|
+
"mdformat-config",
|
|
63
|
+
"mdformat-frontmatter",
|
|
64
|
+
"mdformat-gfm",
|
|
65
|
+
"mdformat-pyproject",
|
|
66
|
+
"mdformat-ruff",
|
|
67
|
+
"mdformat-shfmt",
|
|
68
|
+
"pyproject-fmt",
|
|
69
|
+
"pyright",
|
|
70
|
+
"ruff",
|
|
71
|
+
{ include-group = "test" },
|
|
72
|
+
]
|
|
73
|
+
test = [
|
|
74
|
+
"pytest",
|
|
75
|
+
"pytest-xdist>=3.2",
|
|
76
|
+
]
|
|
77
|
+
ci-build = [
|
|
78
|
+
"cython>=3",
|
|
79
|
+
"setuptools>=84",
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
[tool.hatch]
|
|
83
|
+
metadata.hooks.fancy-pypi-readme.content-type = "text/markdown"
|
|
84
|
+
metadata.hooks.fancy-pypi-readme.fragments = [ { path = "README.md" } ]
|
|
85
|
+
build.targets.wheel.packages = [ "src/sg_token_broker" ]
|
|
86
|
+
build.targets.sdist.include = [ "/README.md", "/src" ]
|
|
87
|
+
|
|
88
|
+
# Keep checkout links relative; package links target this release.
|
|
89
|
+
[[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]]
|
|
90
|
+
pattern = '(!\[[^\]\n]*\]\()(?![A-Za-z][A-Za-z0-9+.-]*:|[/#])(?:\./)?([^\s)]+)(\))'
|
|
91
|
+
replacement = '\1https://raw.githubusercontent.com/dactylo/sg-token-broker/v$HFPR_VERSION/\2\3'
|
|
92
|
+
|
|
93
|
+
[[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]]
|
|
94
|
+
pattern = '(?<!!)(\[[^\]\n]+\]\()(?![A-Za-z][A-Za-z0-9+.-]*:|[/#])(?:\./)?([^\s)]+)(\))'
|
|
95
|
+
replacement = '\1https://github.com/dactylo/sg-token-broker/blob/v$HFPR_VERSION/\2\3'
|
|
96
|
+
|
|
97
|
+
[tool.uv]
|
|
98
|
+
# CI supplies native Taplo; mdformat-config 0.2.1 otherwise pulls a Python Taplo wheel.
|
|
99
|
+
exclude-dependencies = [
|
|
100
|
+
{ package = { name = "mdformat-config", version = "0.2.1" }, dependencies = [ "taplo" ] },
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
# ==========================================================
|
|
104
|
+
# Ruff Configuration
|
|
105
|
+
# ==========================================================
|
|
106
|
+
[tool.ruff]
|
|
107
|
+
target-version = "py311"
|
|
108
|
+
line-length = 99
|
|
109
|
+
format.quote-style = "single"
|
|
110
|
+
format.exclude = [ "*.md" ]
|
|
111
|
+
lint.select = [ "ALL" ]
|
|
112
|
+
lint.ignore = [
|
|
113
|
+
"COM812", # Conflicts with the Ruff formatter
|
|
114
|
+
"CPY001", # Copyright notices are not required
|
|
115
|
+
"EM101", # Exception must not use string literal
|
|
116
|
+
"EM102", # Exception must not use f-string literal
|
|
117
|
+
"FBT001", # Boolean positional arg in function definition
|
|
118
|
+
"FBT002", # Boolean default value in function definition
|
|
119
|
+
"Q000", # Conflicts with the Ruff formatter
|
|
120
|
+
"Q003", # Conflicts with the Ruff formatter
|
|
121
|
+
"T201", # print() found
|
|
122
|
+
"TRY003", # Avoid specifying long messages outside exception class
|
|
123
|
+
]
|
|
124
|
+
# Same-file private-member collaboration; retain checking in other files.
|
|
125
|
+
lint.per-file-ignores."scripts/verify_sg_human_session.py" = [ "SLF001" ]
|
|
126
|
+
lint.per-file-ignores."scripts/verify_sg_sudo.py" = [ "SLF001" ]
|
|
127
|
+
lint.per-file-ignores."src/sg_token_broker/_cache.py" = [ "SLF001" ]
|
|
128
|
+
lint.per-file-ignores."src/sg_token_broker/_http.py" = [ "SLF001" ]
|
|
129
|
+
lint.per-file-ignores."src/sg_token_broker/_userauth.py" = [ "SLF001" ]
|
|
130
|
+
lint.per-file-ignores."src/sg_token_broker/_userhttp.py" = [ "SLF001" ]
|
|
131
|
+
lint.per-file-ignores."tests/**/*.py" = [
|
|
132
|
+
"D", # No docstrings required in tests
|
|
133
|
+
"PLR2004", # Allow magic values in tests
|
|
134
|
+
"S101", # Allow asserts in tests
|
|
135
|
+
"S603", # Allow subprocess calls in tests
|
|
136
|
+
"S607", # Allow partial executable paths in tests
|
|
137
|
+
"SLF001", # Tests intentionally inspect and patch private state
|
|
138
|
+
]
|
|
139
|
+
lint.pydocstyle.convention = "google"
|
|
140
|
+
|
|
141
|
+
[tool.pyproject-fmt]
|
|
142
|
+
max_supported_python = "3.15"
|
|
143
|
+
|
|
144
|
+
# ==========================================================
|
|
145
|
+
# Pyright Configuration
|
|
146
|
+
# ==========================================================
|
|
147
|
+
[tool.pyright]
|
|
148
|
+
pythonVersion = "3.11" # Keep in sync with tool.ruff.target-version
|
|
149
|
+
typeCheckingMode = "strict"
|
|
150
|
+
extraPaths = [ ".", "src" ]
|
|
151
|
+
executionEnvironments = [
|
|
152
|
+
{ root = "tests", reportPrivateUsage = "none" },
|
|
153
|
+
{ root = "." },
|
|
154
|
+
]
|
|
155
|
+
|
|
156
|
+
# ==========================================================
|
|
157
|
+
# Pytest Configuration
|
|
158
|
+
# ==========================================================
|
|
159
|
+
[tool.pytest]
|
|
160
|
+
ini_options.testpaths = [ "tests" ]
|
|
161
|
+
ini_options.pythonpath = [ "src" ]
|
|
162
|
+
ini_options.addopts = [ "-q", "--strict-markers", "--tb=short" ]
|
|
163
|
+
ini_options.markers = [ "slow: marks tests as slow (deselect with '-m \"not slow\"')" ]
|
|
164
|
+
ini_options.faulthandler_timeout = 300
|
|
165
|
+
|
|
166
|
+
# ==========================================================
|
|
167
|
+
# Mdformat Configuration (Requires mdformat-pyproject)
|
|
168
|
+
# ==========================================================
|
|
169
|
+
[tool.mdformat]
|
|
170
|
+
wrap = 99 # Keep in sync with tool.ruff.line-length
|
|
171
|
+
number = true
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""sg-token-broker: temporary, scoped, audited SG credentials.
|
|
2
|
+
|
|
3
|
+
The broker services hold master SG script keys and dispense SG session or REST
|
|
4
|
+
tokens to authenticated callers. REST tokens have a hard SG expiry, while
|
|
5
|
+
session tokens follow SG's sliding inactivity lifetime. Broker cache TTLs
|
|
6
|
+
govern token reuse; they do not define a session token's SG lifetime. This
|
|
7
|
+
package provides the services and their client libraries.
|
|
8
|
+
|
|
9
|
+
Use the `sg-token-broker` CLI to serve or request tokens. Python callers use
|
|
10
|
+
`BrokerClient` for app tokens or `UserTokenClient` for user tokens; their
|
|
11
|
+
settings come from `SG_TOKEN_BROKER_*` and `SG_USER_TOKEN_*` environment
|
|
12
|
+
variables, respectively.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from sg_token_broker._client import (
|
|
16
|
+
BrokerClient,
|
|
17
|
+
BrokerClientError,
|
|
18
|
+
ClientOptions,
|
|
19
|
+
TokenResponse,
|
|
20
|
+
fetch_token,
|
|
21
|
+
)
|
|
22
|
+
from sg_token_broker._userclient import UserToken, UserTokenClient, UserTokenClientError
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
'BrokerClient',
|
|
26
|
+
'BrokerClientError',
|
|
27
|
+
'ClientOptions',
|
|
28
|
+
'TokenResponse',
|
|
29
|
+
'UserToken',
|
|
30
|
+
'UserTokenClient',
|
|
31
|
+
'UserTokenClientError',
|
|
32
|
+
'fetch_token',
|
|
33
|
+
]
|