Skip to content

Commit 40d6c70

Browse files
committed
Initial commit
0 parents  commit 40d6c70

File tree

17 files changed

+3017
-0
lines changed

17 files changed

+3017
-0
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Entry conditions:
2+
# - `setup/checkout` has already happened
3+
# - working dir is the root directory of your project (e.g. `reflex/`).
4+
# - You have a `uv.lock` file in the root directory of your project
5+
# - You have a `pyproject.toml` file in the root directory of your project
6+
#
7+
# Exit conditions:
8+
# - Python of version `python-version` is ready to be invoked as `python`.
9+
# - Uv of version `uv-version` is ready to be invoked as `uv`.
10+
# - If `run-uv-sync` is true, deps as defined in `pyproject.toml` will have been installed into the venv at `create-venv-at-path`.
11+
12+
name: "Setup Reflex build environment"
13+
description: "Sets up Python, install uv (cached), install project deps (cached)"
14+
inputs:
15+
python-version:
16+
description: "Python version setup"
17+
required: true
18+
uv-version:
19+
description: "Uv version to install"
20+
required: false
21+
default: "0.8.0"
22+
run-uv-sync:
23+
description: "Whether to run uv sync on current dir"
24+
required: false
25+
default: false
26+
create-venv-at-path:
27+
description: "Path to venv (if uv sync is enabled)"
28+
required: false
29+
default: ".venv"
30+
31+
runs:
32+
using: "composite"
33+
steps:
34+
- name: Install UV
35+
uses: astral-sh/setup-uv@v5
36+
with:
37+
version: ${{ inputs.uv-version }}
38+
python-version: ${{ inputs.python-version }}
39+
enable-cache: true
40+
prune-cache: false
41+
cache-dependency-glob: "uv.lock"
42+
43+
- name: Restore cached project python deps
44+
id: restore-pydeps-cache
45+
uses: actions/cache/restore@v4
46+
with:
47+
path: ${{ inputs.create-venv-at-path }}
48+
key: ${{ runner.os }}-python-${{ inputs.python-version }}-pydeps-${{ hashFiles('**/uv.lock') }}
49+
50+
- if: ${{ inputs.run-uv-sync == 'true' && steps.restore-pydeps-cache.outputs.cache-hit != 'true' }}
51+
name: Run uv sync (will get cached)
52+
# We skip over installing the root package (the current project code under CI)
53+
# Root package should not be cached - its content is not reflected in uv.lock / cache key
54+
shell: bash
55+
run: |
56+
uv sync --all-extras --dev --no-install-project --prerelease=allow
57+
58+
- if: steps.restore-pydeps-cache.outputs.cache-hit != 'true'
59+
name: Save Python deps to cache
60+
uses: actions/cache/save@v4
61+
with:
62+
path: ${{ inputs.create-venv-at-path }}
63+
key: ${{ steps.restore-pydeps-cache.outputs.cache-primary-key }}
64+
65+
- if: ${{ inputs.run-uv-sync == 'true' }}
66+
name: Run uv sync (root package)
67+
# Here we really install the root package (the current project code under CI).env:
68+
# This should not be cached.
69+
shell: bash
70+
run: |
71+
uv sync --all-extras --dev

.github/workflows/export-demos.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: export-demos
2+
3+
concurrency:
4+
group: ${{ github.workflow }}-${{ github.event.pull_request.id }}
5+
cancel-in-progress: true
6+
7+
on:
8+
pull_request:
9+
branches: ["main"]
10+
paths-ignore:
11+
- "**/*.md"
12+
workflow_dispatch:
13+
14+
permissions:
15+
contents: read
16+
17+
jobs:
18+
demo-export-tests:
19+
timeout-minutes: 30
20+
strategy:
21+
fail-fast: false
22+
matrix:
23+
python-version: ["3.11.11", "3.12.8", "3.13.1"]
24+
runs-on: ubuntu-22.04
25+
26+
steps:
27+
- uses: actions/checkout@v4
28+
with:
29+
fetch-depth: 0 # Fetch all history and tags for proper versioning
30+
- uses: ./.github/actions/setup_build_env
31+
with:
32+
python-version: ${{ matrix.python-version }}
33+
run-uv-sync: true
34+
35+
- name: Install demo requirements
36+
run: |
37+
cd demos
38+
uv pip install --prerelease=allow -r requirements.txt
39+
40+
- name: Test demo export
41+
env:
42+
REFLEX_ACCESS_TOKEN: ${{ secrets.REFLEX_ACCESS_TOKEN }}
43+
run: |
44+
cd demos
45+
uv run --no-sync reflex --version
46+
uv run --no-sync reflex export

.github/workflows/pre-commit.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: pre-commit
2+
3+
on:
4+
pull_request:
5+
branches: ["main"]
6+
push:
7+
branches: ["main"]
8+
9+
jobs:
10+
pre-commit:
11+
timeout-minutes: 30
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v4
15+
- uses: ./.github/actions/setup_build_env
16+
with:
17+
python-version: 3.13
18+
run-uv-sync: true
19+
- run: uv run pre-commit run --all-files --show-diff-on-failure
20+
env:
21+
SKIP: update-pyi-files

.github/workflows/publish.yml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
name: Build and Publish
2+
3+
on:
4+
release:
5+
types: [published]
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: read # Required for checkout
10+
id-token: write # For trusted publishing if using OIDC
11+
12+
jobs:
13+
build:
14+
runs-on: ubuntu-latest
15+
steps:
16+
- name: Checkout repository
17+
uses: actions/checkout@v4
18+
with:
19+
fetch-depth: 0 # Fetch all history for tags
20+
21+
- name: Set up Python
22+
uses: actions/setup-python@v5
23+
with:
24+
python-version: "3.10"
25+
26+
- name: Install UV
27+
run: |
28+
pip install uv
29+
30+
- name: Build Wheel (without sdist)
31+
run: uv build --wheel
32+
33+
- name: Upload wheel artifact
34+
uses: actions/upload-artifact@v4
35+
with:
36+
name: built-wheel
37+
path: dist/*.whl
38+
retention-days: 1 # Keep for 1 day
39+
40+
publish:
41+
needs: build
42+
runs-on: ubuntu-latest
43+
steps:
44+
- name: Checkout repository
45+
uses: actions/checkout@v4
46+
with:
47+
fetch-depth: 0 # Fetch all history for tags
48+
- name: Set up Python
49+
uses: actions/setup-python@v5
50+
with:
51+
python-version: "3.10"
52+
- name: Download all compiled wheels
53+
uses: actions/download-artifact@v4
54+
with:
55+
path: dist/
56+
name: built-wheel
57+
# pattern: reflex_enterprise*.whl
58+
merge-multiple: true
59+
- name: List dist folder contents (for debugging)
60+
run: |
61+
pwd
62+
echo "-------"
63+
ls -l
64+
echo "-------"
65+
ls -l dist/
66+
- name: Install UV
67+
run: |
68+
pip install uv
69+
70+
- name: Publish to PyPI
71+
run: uv publish --token ${{ secrets.PYPI_API_TOKEN }}

.gitignore

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
**/.DS_Store
2+
**/*.pyc
3+
assets/external/*
4+
dist/*
5+
examples/
6+
.web
7+
.states
8+
.idea
9+
.vscode
10+
.coverage
11+
.coverage.*
12+
.venv
13+
venv
14+
.pyi_generator_last_run
15+
.pyi_generator_diff
16+
reflex.db
17+
.codspeed
18+
*.egg-info

.pre-commit-config.yaml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
fail_fast: true
2+
3+
repos:
4+
5+
- repo: https://github.com/charliermarsh/ruff-pre-commit
6+
rev: v0.9.3
7+
hooks:
8+
- id: ruff-format
9+
args: [reflex_azure_auth]
10+
- id: ruff
11+
args: ["--fix", "--exit-non-zero-on-fix"]
12+
exclude: '^integration/benchmarks/'
13+
14+
- repo: https://github.com/codespell-project/codespell
15+
rev: v2.3.0
16+
hooks:
17+
- id: codespell
18+
args: ["reflex_azure_auth"]
19+
20+
- repo: https://github.com/RobertCraigie/pyright-python
21+
rev: v1.1.396
22+
hooks:
23+
- id: pyright
24+
args: [reflex_azure_auth]
25+
language: system

README.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# reflex-azure-auth
2+
3+
This package requires the `reflex_enterprise` package to be installed.
4+
5+
## Installation
6+
7+
```bash
8+
pip install reflex-azure-auth
9+
```
10+
11+
## Usage
12+
13+
### Set Up an Azure (Microsoft identity platform) Application
14+
15+
Create a new Application (App Registration) in the Azure portal and set up a .env file with the following variables:
16+
17+
```env
18+
AZURE_CLIENT_ID=your_client_id
19+
AZURE_CLIENT_SECRET=your_client_secret
20+
AZURE_ISSUER_URI=your tenant issuer or authority URL
21+
```
22+
23+
Reflex will need to access these variables to authenticate users via OpenID Connect on the Microsoft identity platform.
24+
25+
#### Step-by-step: App Registration
26+
27+
1. Sign in to the Azure portal and open "Azure Active Directory" → "App registrations".
28+
2. Click "New registration".
29+
- Name: choose a friendly name (example: "Reflex Demo App").
30+
- Supported account types: choose the tenant(s) you want (single or multi-tenant).
31+
- Redirect URI: add the authorization callback path for your app, e.g. `https://your-app.example.com/authorization-code/callback` (use `http://localhost:3000/authorization-code/callback` for local development).
32+
3. Register the app and copy the "Application (client) ID" → this is `AZURE_CLIENT_ID`.
33+
4. Under "Certificates & secrets" create a new client secret and copy the value → this is `AZURE_CLIENT_SECRET`.
34+
5. Under "Expose an API" or "API permissions" add the scopes your app needs. For typical OpenID Connect sign-in, request the `openid`, `profile`, and `email` scopes. If you need access to a custom API, expose an application ID URI (e.g. `api://<client-id>`) and create delegated scopes.
35+
6. Determine your issuer (authority) URL:
36+
- For a single tenant: `https://login.microsoftonline.com/<your-tenant-id>`
37+
- For common/multi-tenant flows: `https://login.microsoftonline.com/common`
38+
Use the `AZURE_ISSUER_URI` env var to set this (you can include the `/v2.0` suffix or we default to `v2.0` for endpoint assembly).
39+
40+
Example .env (local development):
41+
42+
```env
43+
AZURE_CLIENT_ID=00000000-0000-0000-0000-000000000000
44+
AZURE_CLIENT_SECRET=very-secret-value
45+
AZURE_ISSUER_URI=https://login.microsoftonline.com/common
46+
AZURE_AUDIENCE=api://default
47+
```
48+
49+
Notes:
50+
- Redirect URIs must match exactly. For Reflex demo pages running locally, use the full local URL including the `/authorization-code/callback` path.
51+
- Use `openid email profile` in the authorization request to receive an ID token containing standard claims (sub, name, email).
52+
- When testing with a real tenant, use the tenant-specific issuer URL (recommended for production).
53+
54+
### Register Auth Callback
55+
56+
```python
57+
from reflex_enterprise import App
58+
from reflex_azure_auth import register_auth_endpoints
59+
60+
...
61+
62+
app = App()
63+
register_auth_endpoints(app)
64+
```
65+
66+
### Check `AzureAuthState.userinfo` for user identity/validity
67+
68+
```python
69+
import reflex as rx
70+
from reflex_azure_auth import AzureAuthState
71+
72+
@rx.page()
73+
def index():
74+
return rx.container(
75+
rx.vstack(
76+
rx.heading("Azure (Microsoft) Auth Demo"),
77+
rx.cond(
78+
rx.State.is_hydrated,
79+
rx.cond(
80+
AzureAuthState.userinfo,
81+
rx.vstack(
82+
rx.text(f"Welcome, {AzureAuthState.userinfo["name"]}!"),
83+
rx.text(AzureAuthState.userinfo.to_string()),
84+
rx.button("Logout", on_click=AzureAuthState.redirect_to_logout),
85+
),
86+
rx.button("Log In with Microsoft", on_click=AzureAuthState.redirect_to_login),
87+
),
88+
rx.spinner(),
89+
),
90+
),
91+
)
92+
```
93+
94+
### Validate the Tokens
95+
96+
tokens to ensure they have not been tampered with. Use
97+
Before performing privileged backend operations, it is important to validate the
98+
tokens to ensure they have not been tampered with. Use
99+
`AzureAuthState._validate_tokens()` helper method to validate the tokens.

demos/.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.web
2+
__pycache__/
3+
*.db
4+
.states
5+
*.py[cod]
6+
assets/external/

demos/assets/favicon.ico

4.19 KB
Binary file not shown.

demos/azure/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)