Repository files navigation

ZitAuth πŸ›‘οΈ ✨

ZitAuth is a centralized authentication gateway that transforms Zitadel integration from a headache into a breeze. One clean API for all your appsβ€”web, mobile, and backend services.

Why ZitAuth? Because your applications shouldn't care about JWT validation, JWKS endpoints, or OIDC flows. They should just work.

✨ Key Features

πŸ” Bulletproof User Authentication: OIDC login with PKCE flow
πŸ€– Effortless Service-to-Service Auth: M2M authentication with JWT Bearer Grant
βœ… One-Stop Token Validation: Single /validate endpoint handles all tokens
🎯 Ready-to-Run Examples: Complete user and machine authentication simulation
🐍 Dual Implementation: Available in both Python (FastAPI) and Node.js (Express)

πŸ“Š Architecture Diagram

graph TD
subgraph "Clients"
User[πŸ‘€ User]
M2MClient[πŸ’» Backend Service]
end
subgraph "Application Layer"
SPA[🌐 SPA / Web App]
ProtectedAPI[πŸ“¦ Your Protected API]
end
subgraph "Authentication Core"
ZitAuth[πŸ›‘οΈ ZitAuth Gateway]
Zitadel[πŸ” Zitadel IdP]
end
%% User Authentication Flow
User -- "Initiates Login" --> SPA
SPA -- "Redirects for Auth" --> ZitAuth
ZitAuth -- "Handles OIDC Flow" --> Zitadel
Zitadel -- "Authenticates & Issues Code" --> ZitAuth
ZitAuth -- "Exchanges Code for Token" --> Zitadel
ZitAuth -- "Returns Token" --> SPA
SPA -- "Calls API with User Token" --> ProtectedAPI
%% M2M Authentication Flow
M2MClient -- "Requests M2M Token" --> ZitAuth
ZitAuth -- "Handles JWT Bearer Grant" --> Zitadel
Zitadel -- "Issues M2M Token" --> ZitAuth
ZitAuth -- "Returns Token" --> M2MClient
M2MClient -- "Calls API with M2M Token" --> ProtectedAPI
%% Centralized Validation
ProtectedAPI -- "Validates Token via Gateway" --> ZitAuth
Loading

πŸš€ Quick Start

Prerequisites

  • Docker and Docker Compose
  • Python 3.11+
  • pip for installing dependencies

Step 1: Set Up the Zitadel Environment

  • The provided docker-compose.yaml file is used to set up a local Zitadel instance. You can also use Zitadel hosted on the cloud.

    docker compose up -d
  • You can access the Zitadel Console at http://localhost:8080.

Step 2: Configure Zitadel

  • After starting Zitadel, log in to the console at http://localhost:8080 using these creds:

    • username: zitadel-admin@zitadel.localhost
    • password: Password1!
  • You will need to create a project and application within it (for mobile login flow) and a service user (for m2m flow) and configure login policies (Required for User registration)

    Click to expand Zitadel Application Configuration
    • In your project, create a new application of type User Agent
    • Select authentication method as PKCE, toggle the Development mode to allow redirect to http
    • Configure the redirect URI as http://localhost:8000/api/v1/callback
    • After creating the application, Go to the Token Settings tab and select Auth Token Type as JWT
    • Go to the URLs tab and note down the urls and client id in .env file
    Click to expand Zitadel Service User Configuration
    • In the Zitadel console, go to Users Section and then to the Service Users tab
    • Click on the New button
    • Fill basic details and select the Access Token Type as JWT
    • Go to Keys tab and add a new key of type JSON and download it
    • Save this file to a secure location in your project. Provide the path to this file in the .env file
    Click to expand Zitadel Login Policy Configuration - Navigate to the `Default Settings` setion on the zitadel console - Go to the `External Links` tab in the `Other` subsection - Configure `Link to Terms of Service` and `Link to Privacy Policy` (or use any dummy links for demo) - Click `Save`

Step 3: Configure the ZitAuth Service

  1. Create the .env file by copying the example:

    cp .env.example .env
  2. Edit the .env file:

    • Fill the environment variables with the information received from the step before
  3. Install dependencies:

    pip install -r requirements.txt

πŸƒ Running the Services

The start.sh script is provided to run the main components. You can inspect the script to see the individual commands.

Start the main services:

# This will start ZitAuth on port 8000
uvicorn python.main:app --reload --port 8000

Note - For running in nodejs, refer to nodejs/README.md

πŸ› οΈ Testing

Testing the User Login Flow (SPA)

ZitAuth SPA setup

  1. Start the SPA app:

    uvicorn examples.spa_app.main:app --reload --port 3001
  2. Open your browser and navigate to the SPA at http://127.0.0.1:3001

  3. Click the "Login via ZitAuth" button. You will be redirected to the Zitadel login page

  4. Log in with a user or register one

  5. After a successful login, you will be redirected back to the SPA, and the status will show "Access token received"

  6. Click Call Protected Endpoint and Fetch User Info to test the authenticated API calls

Testing the Machine-to-Machine (M2M) Flow

  1. Ensure the main services (ZitAuth Gateway and SPA App) are running

  2. In a new terminal, run the M2M simulation script:

    python examples/m2m_sim.py
  3. Observe the logs. The script will request an M2M token, receive it, and use it to successfully call the protected API

πŸ—οΈ Project Structure:

.
β”œβ”€β”€ docker-compose.yaml # Sets up Zitadel server locally
β”œβ”€β”€ examples/
β”‚ β”œβ”€β”€ m2m_sim.py # Simulates the local service (M2M)
β”‚ └── spa_app/ # Simulates the mobile/web application
β”œβ”€β”€ python/
β”‚ β”œβ”€β”€ client.py # The core ZitadelClient abstraction layer
β”‚ β”œβ”€β”€ main.py # The FastAPI service (ZitAuth Gateway)
β”‚ └── utils.py # Helper functions
β”œβ”€β”€ .env.example # Template for environment variables
β”œβ”€β”€ requirements.txt # Python dependencies
└── start.sh # Helper script to run services

βš™οΈ API Documentation

Click to expand API Endpoint Documentation

GET /api/v1/login

Initiates the OIDC user login flow. This endpoint is intended to be used by a browser, which will be redirected.

  • Description: Starts the user authentication process by redirecting the user to the Zitadel login page
  • Request: No parameters or headers required
  • Response (Success):
    • HTTP 302 Found: A redirect to the Zitadel authorization endpoint
  • Response (Error):
    • HTTP 400 Bad Request: If there is an internal error generating the login URL

GET /api/v1/callback

Handles the OIDC callback from Zitadel after a user authenticates. This endpoint is used by the browser as part of the redirect flow.

  • Description: Zitadel redirects the user's browser to this endpoint after a successful login. The endpoint exchanges the received authorization code for an access token
  • Request:
    • Query Parameters:
      ParameterDescription
      codeThe authorization code issued by Zitadel
      stateThe unique state string used to prevent CSRF attacks
  • Response (Success):
    • HTTP 302 Found: Redirects the user's browser back to the SPA (SPA_ORIGIN), with the access_token included in the URL hash fragment
  • Response (Error):
    • HTTP 400 Bad Request: If the state is invalid, expired, or the token exchange fails

GET /api/v1/m2m-token

Issues a machine-to-machine (M2M) access token using a pre-configured service account.

  • Description: Allows a trusted backend service to acquire an access token by handling the JWT Bearer Grant flow on behalf of the service
  • Request: No parameters or headers required. The service authenticates itself by its ability to call this endpoint
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON):
      {
      "access_token": "ey..."
      }
  • Response (Error):
    • HTTP 500 Internal Server Error: If the service account file is misconfigured or Zitadel rejects the request

GET /api/v1/validate

Validates an access token and returns the authentication status.

  • Description: A centralized endpoint for any service to delegate token validation. It checks the token's signature against Zitadel's public keys using its JWKS endpoint
  • Request:
    • Headers:
      HeaderDescription
      AuthorizationRequired. The bearer token. Must be in the format Bearer <token>
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON): The decoded claims (payload) of the JWT
      {
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022,
      "exp": 1516242622,
      "iss": "http://localhost:8080"
      }
  • Response (Error):
    • HTTP 400 Bad Request: If the Authorization header is missing or malformed
    • HTTP 401 Unauthorized: If the token is invalid (expired, bad signature, etc.)

GET /api/v1/userinfo

Fetches the user profile from Zitadel's userinfo endpoint using a valid access token.

  • Description: Acts as a secure proxy to Zitadel's userinfo endpoint
  • Request:
    • Headers:
      HeaderDescription
      AuthorizationRequired. The bearer token. Must be in the format Bearer <token>
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON): The user profile information
      {
      "userinfo": {
      "sub": "1234567890",
      "name": "John Doe",
      "email": "john.doe@example.com",
      "email_verified": true
      }
      }
  • Response (Error):
    • HTTP 400 Bad Request: If the Authorization header is missing
    • HTTP 401 Unauthorized: If the access token is invalid or does not have the required scopes

πŸ“š References:

About

πŸ›‘οΈ Zitadel Authentication Abstraction

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

ZitAuth πŸ›‘οΈ ✨

ZitAuth is a centralized authentication gateway that transforms Zitadel integration from a headache into a breeze. One clean API for all your appsβ€”web, mobile, and backend services.

Why ZitAuth? Because your applications shouldn't care about JWT validation, JWKS endpoints, or OIDC flows. They should just work.

✨ Key Features

πŸ” Bulletproof User Authentication: OIDC login with PKCE flow
πŸ€– Effortless Service-to-Service Auth: M2M authentication with JWT Bearer Grant
βœ… One-Stop Token Validation: Single /validate endpoint handles all tokens
🎯 Ready-to-Run Examples: Complete user and machine authentication simulation
🐍 Dual Implementation: Available in both Python (FastAPI) and Node.js (Express)

πŸ“Š Architecture Diagram

graph TD
subgraph "Clients"
User[πŸ‘€ User]
M2MClient[πŸ’» Backend Service]
end
subgraph "Application Layer"
SPA[🌐 SPA / Web App]
ProtectedAPI[πŸ“¦ Your Protected API]
end
subgraph "Authentication Core"
ZitAuth[πŸ›‘οΈ ZitAuth Gateway]
Zitadel[πŸ” Zitadel IdP]
end
%% User Authentication Flow
User -- "Initiates Login" --> SPA
SPA -- "Redirects for Auth" --> ZitAuth
ZitAuth -- "Handles OIDC Flow" --> Zitadel
Zitadel -- "Authenticates & Issues Code" --> ZitAuth
ZitAuth -- "Exchanges Code for Token" --> Zitadel
ZitAuth -- "Returns Token" --> SPA
SPA -- "Calls API with User Token" --> ProtectedAPI
%% M2M Authentication Flow
M2MClient -- "Requests M2M Token" --> ZitAuth
ZitAuth -- "Handles JWT Bearer Grant" --> Zitadel
Zitadel -- "Issues M2M Token" --> ZitAuth
ZitAuth -- "Returns Token" --> M2MClient
M2MClient -- "Calls API with M2M Token" --> ProtectedAPI
%% Centralized Validation
ProtectedAPI -- "Validates Token via Gateway" --> ZitAuth
Loading

πŸš€ Quick Start

Prerequisites

  • Docker and Docker Compose
  • Python 3.11+
  • pip for installing dependencies

Step 1: Set Up the Zitadel Environment

  • The provided docker-compose.yaml file is used to set up a local Zitadel instance. You can also use Zitadel hosted on the cloud.

    docker compose up -d
  • You can access the Zitadel Console at http://localhost:8080.

Step 2: Configure Zitadel

  • After starting Zitadel, log in to the console at http://localhost:8080 using these creds:

    • username: zitadel-admin@zitadel.localhost
    • password: Password1!
  • You will need to create a project and application within it (for mobile login flow) and a service user (for m2m flow) and configure login policies (Required for User registration)

    Click to expand Zitadel Application Configuration
    • In your project, create a new application of type User Agent
    • Select authentication method as PKCE, toggle the Development mode to allow redirect to http
    • Configure the redirect URI as http://localhost:8000/api/v1/callback
    • After creating the application, Go to the Token Settings tab and select Auth Token Type as JWT
    • Go to the URLs tab and note down the urls and client id in .env file
    Click to expand Zitadel Service User Configuration
    • In the Zitadel console, go to Users Section and then to the Service Users tab
    • Click on the New button
    • Fill basic details and select the Access Token Type as JWT
    • Go to Keys tab and add a new key of type JSON and download it
    • Save this file to a secure location in your project. Provide the path to this file in the .env file
    Click to expand Zitadel Login Policy Configuration - Navigate to the `Default Settings` setion on the zitadel console - Go to the `External Links` tab in the `Other` subsection - Configure `Link to Terms of Service` and `Link to Privacy Policy` (or use any dummy links for demo) - Click `Save`

Step 3: Configure the ZitAuth Service

  1. Create the .env file by copying the example:

    cp .env.example .env
  2. Edit the .env file:

    • Fill the environment variables with the information received from the step before
  3. Install dependencies:

    pip install -r requirements.txt

πŸƒ Running the Services

The start.sh script is provided to run the main components. You can inspect the script to see the individual commands.

Start the main services:

# This will start ZitAuth on port 8000
uvicorn python.main:app --reload --port 8000

Note - For running in nodejs, refer to nodejs/README.md

πŸ› οΈ Testing

Testing the User Login Flow (SPA)

ZitAuth SPA setup

  1. Start the SPA app:

    uvicorn examples.spa_app.main:app --reload --port 3001
  2. Open your browser and navigate to the SPA at http://127.0.0.1:3001

  3. Click the "Login via ZitAuth" button. You will be redirected to the Zitadel login page

  4. Log in with a user or register one

  5. After a successful login, you will be redirected back to the SPA, and the status will show "Access token received"

  6. Click Call Protected Endpoint and Fetch User Info to test the authenticated API calls

Testing the Machine-to-Machine (M2M) Flow

  1. Ensure the main services (ZitAuth Gateway and SPA App) are running

  2. In a new terminal, run the M2M simulation script:

    python examples/m2m_sim.py
  3. Observe the logs. The script will request an M2M token, receive it, and use it to successfully call the protected API

πŸ—οΈ Project Structure:

.
β”œβ”€β”€ docker-compose.yaml # Sets up Zitadel server locally
β”œβ”€β”€ examples/
β”‚ β”œβ”€β”€ m2m_sim.py # Simulates the local service (M2M)
β”‚ └── spa_app/ # Simulates the mobile/web application
β”œβ”€β”€ python/
β”‚ β”œβ”€β”€ client.py # The core ZitadelClient abstraction layer
β”‚ β”œβ”€β”€ main.py # The FastAPI service (ZitAuth Gateway)
β”‚ └── utils.py # Helper functions
β”œβ”€β”€ .env.example # Template for environment variables
β”œβ”€β”€ requirements.txt # Python dependencies
└── start.sh # Helper script to run services

βš™οΈ API Documentation

Click to expand API Endpoint Documentation

GET /api/v1/login

Initiates the OIDC user login flow. This endpoint is intended to be used by a browser, which will be redirected.

  • Description: Starts the user authentication process by redirecting the user to the Zitadel login page
  • Request: No parameters or headers required
  • Response (Success):
    • HTTP 302 Found: A redirect to the Zitadel authorization endpoint
  • Response (Error):
    • HTTP 400 Bad Request: If there is an internal error generating the login URL

GET /api/v1/callback

Handles the OIDC callback from Zitadel after a user authenticates. This endpoint is used by the browser as part of the redirect flow.

  • Description: Zitadel redirects the user's browser to this endpoint after a successful login. The endpoint exchanges the received authorization code for an access token
  • Request:
    • Query Parameters:
      ParameterDescription
      codeThe authorization code issued by Zitadel
      stateThe unique state string used to prevent CSRF attacks
  • Response (Success):
    • HTTP 302 Found: Redirects the user's browser back to the SPA (SPA_ORIGIN), with the access_token included in the URL hash fragment
  • Response (Error):
    • HTTP 400 Bad Request: If the state is invalid, expired, or the token exchange fails

GET /api/v1/m2m-token

Issues a machine-to-machine (M2M) access token using a pre-configured service account.

  • Description: Allows a trusted backend service to acquire an access token by handling the JWT Bearer Grant flow on behalf of the service
  • Request: No parameters or headers required. The service authenticates itself by its ability to call this endpoint
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON):
      {
      "access_token": "ey..."
      }
  • Response (Error):
    • HTTP 500 Internal Server Error: If the service account file is misconfigured or Zitadel rejects the request

GET /api/v1/validate

Validates an access token and returns the authentication status.

  • Description: A centralized endpoint for any service to delegate token validation. It checks the token's signature against Zitadel's public keys using its JWKS endpoint
  • Request:
    • Headers:
      HeaderDescription
      AuthorizationRequired. The bearer token. Must be in the format Bearer <token>
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON): The decoded claims (payload) of the JWT
      {
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022,
      "exp": 1516242622,
      "iss": "http://localhost:8080"
      }
  • Response (Error):
    • HTTP 400 Bad Request: If the Authorization header is missing or malformed
    • HTTP 401 Unauthorized: If the token is invalid (expired, bad signature, etc.)

GET /api/v1/userinfo

Fetches the user profile from Zitadel's userinfo endpoint using a valid access token.

  • Description: Acts as a secure proxy to Zitadel's userinfo endpoint
  • Request:
    • Headers:
      HeaderDescription
      AuthorizationRequired. The bearer token. Must be in the format Bearer <token>
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON): The user profile information
      {
      "userinfo": {
      "sub": "1234567890",
      "name": "John Doe",
      "email": "john.doe@example.com",
      "email_verified": true
      }
      }
  • Response (Error):
    • HTTP 400 Bad Request: If the Authorization header is missing
    • HTTP 401 Unauthorized: If the access token is invalid or does not have the required scopes

πŸ“š References:

About

πŸ›‘οΈ Zitadel Authentication Abstraction

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

ZitAuth πŸ›‘οΈ ✨

ZitAuth is a centralized authentication gateway that transforms Zitadel integration from a headache into a breeze. One clean API for all your appsβ€”web, mobile, and backend services.

Why ZitAuth? Because your applications shouldn't care about JWT validation, JWKS endpoints, or OIDC flows. They should just work.

✨ Key Features

πŸ” Bulletproof User Authentication: OIDC login with PKCE flow
πŸ€– Effortless Service-to-Service Auth: M2M authentication with JWT Bearer Grant
βœ… One-Stop Token Validation: Single /validate endpoint handles all tokens
🎯 Ready-to-Run Examples: Complete user and machine authentication simulation
🐍 Dual Implementation: Available in both Python (FastAPI) and Node.js (Express)

πŸ“Š Architecture Diagram

graph TD
subgraph "Clients"
User[πŸ‘€ User]
M2MClient[πŸ’» Backend Service]
end
subgraph "Application Layer"
SPA[🌐 SPA / Web App]
ProtectedAPI[πŸ“¦ Your Protected API]
end
subgraph "Authentication Core"
ZitAuth[πŸ›‘οΈ ZitAuth Gateway]
Zitadel[πŸ” Zitadel IdP]
end
%% User Authentication Flow
User -- "Initiates Login" --> SPA
SPA -- "Redirects for Auth" --> ZitAuth
ZitAuth -- "Handles OIDC Flow" --> Zitadel
Zitadel -- "Authenticates & Issues Code" --> ZitAuth
ZitAuth -- "Exchanges Code for Token" --> Zitadel
ZitAuth -- "Returns Token" --> SPA
SPA -- "Calls API with User Token" --> ProtectedAPI
%% M2M Authentication Flow
M2MClient -- "Requests M2M Token" --> ZitAuth
ZitAuth -- "Handles JWT Bearer Grant" --> Zitadel
Zitadel -- "Issues M2M Token" --> ZitAuth
ZitAuth -- "Returns Token" --> M2MClient
M2MClient -- "Calls API with M2M Token" --> ProtectedAPI
%% Centralized Validation
ProtectedAPI -- "Validates Token via Gateway" --> ZitAuth
Loading

πŸš€ Quick Start

Prerequisites

  • Docker and Docker Compose
  • Python 3.11+
  • pip for installing dependencies

Step 1: Set Up the Zitadel Environment

  • The provided docker-compose.yaml file is used to set up a local Zitadel instance. You can also use Zitadel hosted on the cloud.

    docker compose up -d
  • You can access the Zitadel Console at http://localhost:8080.

Step 2: Configure Zitadel

  • After starting Zitadel, log in to the console at http://localhost:8080 using these creds:

    • username: zitadel-admin@zitadel.localhost
    • password: Password1!
  • You will need to create a project and application within it (for mobile login flow) and a service user (for m2m flow) and configure login policies (Required for User registration)

    Click to expand Zitadel Application Configuration
    • In your project, create a new application of type User Agent
    • Select authentication method as PKCE, toggle the Development mode to allow redirect to http
    • Configure the redirect URI as http://localhost:8000/api/v1/callback
    • After creating the application, Go to the Token Settings tab and select Auth Token Type as JWT
    • Go to the URLs tab and note down the urls and client id in .env file
    Click to expand Zitadel Service User Configuration
    • In the Zitadel console, go to Users Section and then to the Service Users tab
    • Click on the New button
    • Fill basic details and select the Access Token Type as JWT
    • Go to Keys tab and add a new key of type JSON and download it
    • Save this file to a secure location in your project. Provide the path to this file in the .env file
    Click to expand Zitadel Login Policy Configuration - Navigate to the `Default Settings` setion on the zitadel console - Go to the `External Links` tab in the `Other` subsection - Configure `Link to Terms of Service` and `Link to Privacy Policy` (or use any dummy links for demo) - Click `Save`

Step 3: Configure the ZitAuth Service

  1. Create the .env file by copying the example:

    cp .env.example .env
  2. Edit the .env file:

    • Fill the environment variables with the information received from the step before
  3. Install dependencies:

    pip install -r requirements.txt

πŸƒ Running the Services

The start.sh script is provided to run the main components. You can inspect the script to see the individual commands.

Start the main services:

# This will start ZitAuth on port 8000
uvicorn python.main:app --reload --port 8000

Note - For running in nodejs, refer to nodejs/README.md

πŸ› οΈ Testing

Testing the User Login Flow (SPA)

ZitAuth SPA setup

  1. Start the SPA app:

    uvicorn examples.spa_app.main:app --reload --port 3001
  2. Open your browser and navigate to the SPA at http://127.0.0.1:3001

  3. Click the "Login via ZitAuth" button. You will be redirected to the Zitadel login page

  4. Log in with a user or register one

  5. After a successful login, you will be redirected back to the SPA, and the status will show "Access token received"

  6. Click Call Protected Endpoint and Fetch User Info to test the authenticated API calls

Testing the Machine-to-Machine (M2M) Flow

  1. Ensure the main services (ZitAuth Gateway and SPA App) are running

  2. In a new terminal, run the M2M simulation script:

    python examples/m2m_sim.py
  3. Observe the logs. The script will request an M2M token, receive it, and use it to successfully call the protected API

πŸ—οΈ Project Structure:

.
β”œβ”€β”€ docker-compose.yaml # Sets up Zitadel server locally
β”œβ”€β”€ examples/
β”‚ β”œβ”€β”€ m2m_sim.py # Simulates the local service (M2M)
β”‚ └── spa_app/ # Simulates the mobile/web application
β”œβ”€β”€ python/
β”‚ β”œβ”€β”€ client.py # The core ZitadelClient abstraction layer
β”‚ β”œβ”€β”€ main.py # The FastAPI service (ZitAuth Gateway)
β”‚ └── utils.py # Helper functions
β”œβ”€β”€ .env.example # Template for environment variables
β”œβ”€β”€ requirements.txt # Python dependencies
└── start.sh # Helper script to run services

βš™οΈ API Documentation

Click to expand API Endpoint Documentation

GET /api/v1/login

Initiates the OIDC user login flow. This endpoint is intended to be used by a browser, which will be redirected.

  • Description: Starts the user authentication process by redirecting the user to the Zitadel login page
  • Request: No parameters or headers required
  • Response (Success):
    • HTTP 302 Found: A redirect to the Zitadel authorization endpoint
  • Response (Error):
    • HTTP 400 Bad Request: If there is an internal error generating the login URL

GET /api/v1/callback

Handles the OIDC callback from Zitadel after a user authenticates. This endpoint is used by the browser as part of the redirect flow.

  • Description: Zitadel redirects the user's browser to this endpoint after a successful login. The endpoint exchanges the received authorization code for an access token
  • Request:
    • Query Parameters:
      ParameterDescription
      codeThe authorization code issued by Zitadel
      stateThe unique state string used to prevent CSRF attacks
  • Response (Success):
    • HTTP 302 Found: Redirects the user's browser back to the SPA (SPA_ORIGIN), with the access_token included in the URL hash fragment
  • Response (Error):
    • HTTP 400 Bad Request: If the state is invalid, expired, or the token exchange fails

GET /api/v1/m2m-token

Issues a machine-to-machine (M2M) access token using a pre-configured service account.

  • Description: Allows a trusted backend service to acquire an access token by handling the JWT Bearer Grant flow on behalf of the service
  • Request: No parameters or headers required. The service authenticates itself by its ability to call this endpoint
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON):
      {
      "access_token": "ey..."
      }
  • Response (Error):
    • HTTP 500 Internal Server Error: If the service account file is misconfigured or Zitadel rejects the request

GET /api/v1/validate

Validates an access token and returns the authentication status.

  • Description: A centralized endpoint for any service to delegate token validation. It checks the token's signature against Zitadel's public keys using its JWKS endpoint
  • Request:
    • Headers:
      HeaderDescription
      AuthorizationRequired. The bearer token. Must be in the format Bearer <token>
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON): The decoded claims (payload) of the JWT
      {
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022,
      "exp": 1516242622,
      "iss": "http://localhost:8080"
      }
  • Response (Error):
    • HTTP 400 Bad Request: If the Authorization header is missing or malformed
    • HTTP 401 Unauthorized: If the token is invalid (expired, bad signature, etc.)

GET /api/v1/userinfo

Fetches the user profile from Zitadel's userinfo endpoint using a valid access token.

  • Description: Acts as a secure proxy to Zitadel's userinfo endpoint
  • Request:
    • Headers:
      HeaderDescription
      AuthorizationRequired. The bearer token. Must be in the format Bearer <token>
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON): The user profile information
      {
      "userinfo": {
      "sub": "1234567890",
      "name": "John Doe",
      "email": "john.doe@example.com",
      "email_verified": true
      }
      }
  • Response (Error):
    • HTTP 400 Bad Request: If the Authorization header is missing
    • HTTP 401 Unauthorized: If the access token is invalid or does not have the required scopes

πŸ“š References:

About

πŸ›‘οΈ Zitadel Authentication Abstraction

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

ZitAuth πŸ›‘οΈ ✨

ZitAuth is a centralized authentication gateway that transforms Zitadel integration from a headache into a breeze. One clean API for all your appsβ€”web, mobile, and backend services.

Why ZitAuth? Because your applications shouldn't care about JWT validation, JWKS endpoints, or OIDC flows. They should just work.

✨ Key Features

πŸ” Bulletproof User Authentication: OIDC login with PKCE flow
πŸ€– Effortless Service-to-Service Auth: M2M authentication with JWT Bearer Grant
βœ… One-Stop Token Validation: Single /validate endpoint handles all tokens
🎯 Ready-to-Run Examples: Complete user and machine authentication simulation
🐍 Dual Implementation: Available in both Python (FastAPI) and Node.js (Express)

πŸ“Š Architecture Diagram

graph TD
subgraph "Clients"
User[πŸ‘€ User]
M2MClient[πŸ’» Backend Service]
end
subgraph "Application Layer"
SPA[🌐 SPA / Web App]
ProtectedAPI[πŸ“¦ Your Protected API]
end
subgraph "Authentication Core"
ZitAuth[πŸ›‘οΈ ZitAuth Gateway]
Zitadel[πŸ” Zitadel IdP]
end
%% User Authentication Flow
User -- "Initiates Login" --> SPA
SPA -- "Redirects for Auth" --> ZitAuth
ZitAuth -- "Handles OIDC Flow" --> Zitadel
Zitadel -- "Authenticates & Issues Code" --> ZitAuth
ZitAuth -- "Exchanges Code for Token" --> Zitadel
ZitAuth -- "Returns Token" --> SPA
SPA -- "Calls API with User Token" --> ProtectedAPI
%% M2M Authentication Flow
M2MClient -- "Requests M2M Token" --> ZitAuth
ZitAuth -- "Handles JWT Bearer Grant" --> Zitadel
Zitadel -- "Issues M2M Token" --> ZitAuth
ZitAuth -- "Returns Token" --> M2MClient
M2MClient -- "Calls API with M2M Token" --> ProtectedAPI
%% Centralized Validation
ProtectedAPI -- "Validates Token via Gateway" --> ZitAuth
Loading

πŸš€ Quick Start

Prerequisites

  • Docker and Docker Compose
  • Python 3.11+
  • pip for installing dependencies

Step 1: Set Up the Zitadel Environment

  • The provided docker-compose.yaml file is used to set up a local Zitadel instance. You can also use Zitadel hosted on the cloud.

    docker compose up -d
  • You can access the Zitadel Console at http://localhost:8080.

Step 2: Configure Zitadel

  • After starting Zitadel, log in to the console at http://localhost:8080 using these creds:

    • username: zitadel-admin@zitadel.localhost
    • password: Password1!
  • You will need to create a project and application within it (for mobile login flow) and a service user (for m2m flow) and configure login policies (Required for User registration)

    Click to expand Zitadel Application Configuration
    • In your project, create a new application of type User Agent
    • Select authentication method as PKCE, toggle the Development mode to allow redirect to http
    • Configure the redirect URI as http://localhost:8000/api/v1/callback
    • After creating the application, Go to the Token Settings tab and select Auth Token Type as JWT
    • Go to the URLs tab and note down the urls and client id in .env file
    Click to expand Zitadel Service User Configuration
    • In the Zitadel console, go to Users Section and then to the Service Users tab
    • Click on the New button
    • Fill basic details and select the Access Token Type as JWT
    • Go to Keys tab and add a new key of type JSON and download it
    • Save this file to a secure location in your project. Provide the path to this file in the .env file
    Click to expand Zitadel Login Policy Configuration - Navigate to the `Default Settings` setion on the zitadel console - Go to the `External Links` tab in the `Other` subsection - Configure `Link to Terms of Service` and `Link to Privacy Policy` (or use any dummy links for demo) - Click `Save`

Step 3: Configure the ZitAuth Service

  1. Create the .env file by copying the example:

    cp .env.example .env
  2. Edit the .env file:

    • Fill the environment variables with the information received from the step before
  3. Install dependencies:

    pip install -r requirements.txt

πŸƒ Running the Services

The start.sh script is provided to run the main components. You can inspect the script to see the individual commands.

Start the main services:

# This will start ZitAuth on port 8000
uvicorn python.main:app --reload --port 8000

Note - For running in nodejs, refer to nodejs/README.md

πŸ› οΈ Testing

Testing the User Login Flow (SPA)

ZitAuth SPA setup

  1. Start the SPA app:

    uvicorn examples.spa_app.main:app --reload --port 3001
  2. Open your browser and navigate to the SPA at http://127.0.0.1:3001

  3. Click the "Login via ZitAuth" button. You will be redirected to the Zitadel login page

  4. Log in with a user or register one

  5. After a successful login, you will be redirected back to the SPA, and the status will show "Access token received"

  6. Click Call Protected Endpoint and Fetch User Info to test the authenticated API calls

Testing the Machine-to-Machine (M2M) Flow

  1. Ensure the main services (ZitAuth Gateway and SPA App) are running

  2. In a new terminal, run the M2M simulation script:

    python examples/m2m_sim.py
  3. Observe the logs. The script will request an M2M token, receive it, and use it to successfully call the protected API

πŸ—οΈ Project Structure:

.
β”œβ”€β”€ docker-compose.yaml # Sets up Zitadel server locally
β”œβ”€β”€ examples/
β”‚ β”œβ”€β”€ m2m_sim.py # Simulates the local service (M2M)
β”‚ └── spa_app/ # Simulates the mobile/web application
β”œβ”€β”€ python/
β”‚ β”œβ”€β”€ client.py # The core ZitadelClient abstraction layer
β”‚ β”œβ”€β”€ main.py # The FastAPI service (ZitAuth Gateway)
β”‚ └── utils.py # Helper functions
β”œβ”€β”€ .env.example # Template for environment variables
β”œβ”€β”€ requirements.txt # Python dependencies
└── start.sh # Helper script to run services

βš™οΈ API Documentation

Click to expand API Endpoint Documentation

GET /api/v1/login

Initiates the OIDC user login flow. This endpoint is intended to be used by a browser, which will be redirected.

  • Description: Starts the user authentication process by redirecting the user to the Zitadel login page
  • Request: No parameters or headers required
  • Response (Success):
    • HTTP 302 Found: A redirect to the Zitadel authorization endpoint
  • Response (Error):
    • HTTP 400 Bad Request: If there is an internal error generating the login URL

GET /api/v1/callback

Handles the OIDC callback from Zitadel after a user authenticates. This endpoint is used by the browser as part of the redirect flow.

  • Description: Zitadel redirects the user's browser to this endpoint after a successful login. The endpoint exchanges the received authorization code for an access token
  • Request:
    • Query Parameters:
      ParameterDescription
      codeThe authorization code issued by Zitadel
      stateThe unique state string used to prevent CSRF attacks
  • Response (Success):
    • HTTP 302 Found: Redirects the user's browser back to the SPA (SPA_ORIGIN), with the access_token included in the URL hash fragment
  • Response (Error):
    • HTTP 400 Bad Request: If the state is invalid, expired, or the token exchange fails

GET /api/v1/m2m-token

Issues a machine-to-machine (M2M) access token using a pre-configured service account.

  • Description: Allows a trusted backend service to acquire an access token by handling the JWT Bearer Grant flow on behalf of the service
  • Request: No parameters or headers required. The service authenticates itself by its ability to call this endpoint
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON):
      {
      "access_token": "ey..."
      }
  • Response (Error):
    • HTTP 500 Internal Server Error: If the service account file is misconfigured or Zitadel rejects the request

GET /api/v1/validate

Validates an access token and returns the authentication status.

  • Description: A centralized endpoint for any service to delegate token validation. It checks the token's signature against Zitadel's public keys using its JWKS endpoint
  • Request:
    • Headers:
      HeaderDescription
      AuthorizationRequired. The bearer token. Must be in the format Bearer <token>
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON): The decoded claims (payload) of the JWT
      {
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022,
      "exp": 1516242622,
      "iss": "http://localhost:8080"
      }
  • Response (Error):
    • HTTP 400 Bad Request: If the Authorization header is missing or malformed
    • HTTP 401 Unauthorized: If the token is invalid (expired, bad signature, etc.)

GET /api/v1/userinfo

Fetches the user profile from Zitadel's userinfo endpoint using a valid access token.

  • Description: Acts as a secure proxy to Zitadel's userinfo endpoint
  • Request:
    • Headers:
      HeaderDescription
      AuthorizationRequired. The bearer token. Must be in the format Bearer <token>
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON): The user profile information
      {
      "userinfo": {
      "sub": "1234567890",
      "name": "John Doe",
      "email": "john.doe@example.com",
      "email_verified": true
      }
      }
  • Response (Error):
    • HTTP 400 Bad Request: If the Authorization header is missing
    • HTTP 401 Unauthorized: If the access token is invalid or does not have the required scopes

πŸ“š References:

About

πŸ›‘οΈ Zitadel Authentication Abstraction

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

ZitAuth πŸ›‘οΈ ✨

ZitAuth is a centralized authentication gateway that transforms Zitadel integration from a headache into a breeze. One clean API for all your appsβ€”web, mobile, and backend services.

Why ZitAuth? Because your applications shouldn't care about JWT validation, JWKS endpoints, or OIDC flows. They should just work.

✨ Key Features

πŸ” Bulletproof User Authentication: OIDC login with PKCE flow
πŸ€– Effortless Service-to-Service Auth: M2M authentication with JWT Bearer Grant
βœ… One-Stop Token Validation: Single /validate endpoint handles all tokens
🎯 Ready-to-Run Examples: Complete user and machine authentication simulation
🐍 Dual Implementation: Available in both Python (FastAPI) and Node.js (Express)

πŸ“Š Architecture Diagram

graph TD
subgraph "Clients"
User[πŸ‘€ User]
M2MClient[πŸ’» Backend Service]
end
subgraph "Application Layer"
SPA[🌐 SPA / Web App]
ProtectedAPI[πŸ“¦ Your Protected API]
end
subgraph "Authentication Core"
ZitAuth[πŸ›‘οΈ ZitAuth Gateway]
Zitadel[πŸ” Zitadel IdP]
end
%% User Authentication Flow
User -- "Initiates Login" --> SPA
SPA -- "Redirects for Auth" --> ZitAuth
ZitAuth -- "Handles OIDC Flow" --> Zitadel
Zitadel -- "Authenticates & Issues Code" --> ZitAuth
ZitAuth -- "Exchanges Code for Token" --> Zitadel
ZitAuth -- "Returns Token" --> SPA
SPA -- "Calls API with User Token" --> ProtectedAPI
%% M2M Authentication Flow
M2MClient -- "Requests M2M Token" --> ZitAuth
ZitAuth -- "Handles JWT Bearer Grant" --> Zitadel
Zitadel -- "Issues M2M Token" --> ZitAuth
ZitAuth -- "Returns Token" --> M2MClient
M2MClient -- "Calls API with M2M Token" --> ProtectedAPI
%% Centralized Validation
ProtectedAPI -- "Validates Token via Gateway" --> ZitAuth
Loading

πŸš€ Quick Start

Prerequisites

  • Docker and Docker Compose
  • Python 3.11+
  • pip for installing dependencies

Step 1: Set Up the Zitadel Environment

  • The provided docker-compose.yaml file is used to set up a local Zitadel instance. You can also use Zitadel hosted on the cloud.

    docker compose up -d
  • You can access the Zitadel Console at http://localhost:8080.

Step 2: Configure Zitadel

  • After starting Zitadel, log in to the console at http://localhost:8080 using these creds:

    • username: zitadel-admin@zitadel.localhost
    • password: Password1!
  • You will need to create a project and application within it (for mobile login flow) and a service user (for m2m flow) and configure login policies (Required for User registration)

    Click to expand Zitadel Application Configuration
    • In your project, create a new application of type User Agent
    • Select authentication method as PKCE, toggle the Development mode to allow redirect to http
    • Configure the redirect URI as http://localhost:8000/api/v1/callback
    • After creating the application, Go to the Token Settings tab and select Auth Token Type as JWT
    • Go to the URLs tab and note down the urls and client id in .env file
    Click to expand Zitadel Service User Configuration
    • In the Zitadel console, go to Users Section and then to the Service Users tab
    • Click on the New button
    • Fill basic details and select the Access Token Type as JWT
    • Go to Keys tab and add a new key of type JSON and download it
    • Save this file to a secure location in your project. Provide the path to this file in the .env file
    Click to expand Zitadel Login Policy Configuration - Navigate to the `Default Settings` setion on the zitadel console - Go to the `External Links` tab in the `Other` subsection - Configure `Link to Terms of Service` and `Link to Privacy Policy` (or use any dummy links for demo) - Click `Save`

Step 3: Configure the ZitAuth Service

  1. Create the .env file by copying the example:

    cp .env.example .env
  2. Edit the .env file:

    • Fill the environment variables with the information received from the step before
  3. Install dependencies:

    pip install -r requirements.txt

πŸƒ Running the Services

The start.sh script is provided to run the main components. You can inspect the script to see the individual commands.

Start the main services:

# This will start ZitAuth on port 8000
uvicorn python.main:app --reload --port 8000

Note - For running in nodejs, refer to nodejs/README.md

πŸ› οΈ Testing

Testing the User Login Flow (SPA)

ZitAuth SPA setup

  1. Start the SPA app:

    uvicorn examples.spa_app.main:app --reload --port 3001
  2. Open your browser and navigate to the SPA at http://127.0.0.1:3001

  3. Click the "Login via ZitAuth" button. You will be redirected to the Zitadel login page

  4. Log in with a user or register one

  5. After a successful login, you will be redirected back to the SPA, and the status will show "Access token received"

  6. Click Call Protected Endpoint and Fetch User Info to test the authenticated API calls

Testing the Machine-to-Machine (M2M) Flow

  1. Ensure the main services (ZitAuth Gateway and SPA App) are running

  2. In a new terminal, run the M2M simulation script:

    python examples/m2m_sim.py
  3. Observe the logs. The script will request an M2M token, receive it, and use it to successfully call the protected API

πŸ—οΈ Project Structure:

.
β”œβ”€β”€ docker-compose.yaml # Sets up Zitadel server locally
β”œβ”€β”€ examples/
β”‚ β”œβ”€β”€ m2m_sim.py # Simulates the local service (M2M)
β”‚ └── spa_app/ # Simulates the mobile/web application
β”œβ”€β”€ python/
β”‚ β”œβ”€β”€ client.py # The core ZitadelClient abstraction layer
β”‚ β”œβ”€β”€ main.py # The FastAPI service (ZitAuth Gateway)
β”‚ └── utils.py # Helper functions
β”œβ”€β”€ .env.example # Template for environment variables
β”œβ”€β”€ requirements.txt # Python dependencies
└── start.sh # Helper script to run services

βš™οΈ API Documentation

Click to expand API Endpoint Documentation

GET /api/v1/login

Initiates the OIDC user login flow. This endpoint is intended to be used by a browser, which will be redirected.

  • Description: Starts the user authentication process by redirecting the user to the Zitadel login page
  • Request: No parameters or headers required
  • Response (Success):
    • HTTP 302 Found: A redirect to the Zitadel authorization endpoint
  • Response (Error):
    • HTTP 400 Bad Request: If there is an internal error generating the login URL

GET /api/v1/callback

Handles the OIDC callback from Zitadel after a user authenticates. This endpoint is used by the browser as part of the redirect flow.

  • Description: Zitadel redirects the user's browser to this endpoint after a successful login. The endpoint exchanges the received authorization code for an access token
  • Request:
    • Query Parameters:
      ParameterDescription
      codeThe authorization code issued by Zitadel
      stateThe unique state string used to prevent CSRF attacks
  • Response (Success):
    • HTTP 302 Found: Redirects the user's browser back to the SPA (SPA_ORIGIN), with the access_token included in the URL hash fragment
  • Response (Error):
    • HTTP 400 Bad Request: If the state is invalid, expired, or the token exchange fails

GET /api/v1/m2m-token

Issues a machine-to-machine (M2M) access token using a pre-configured service account.

  • Description: Allows a trusted backend service to acquire an access token by handling the JWT Bearer Grant flow on behalf of the service
  • Request: No parameters or headers required. The service authenticates itself by its ability to call this endpoint
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON):
      {
      "access_token": "ey..."
      }
  • Response (Error):
    • HTTP 500 Internal Server Error: If the service account file is misconfigured or Zitadel rejects the request

GET /api/v1/validate

Validates an access token and returns the authentication status.

  • Description: A centralized endpoint for any service to delegate token validation. It checks the token's signature against Zitadel's public keys using its JWKS endpoint
  • Request:
    • Headers:
      HeaderDescription
      AuthorizationRequired. The bearer token. Must be in the format Bearer <token>
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON): The decoded claims (payload) of the JWT
      {
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022,
      "exp": 1516242622,
      "iss": "http://localhost:8080"
      }
  • Response (Error):
    • HTTP 400 Bad Request: If the Authorization header is missing or malformed
    • HTTP 401 Unauthorized: If the token is invalid (expired, bad signature, etc.)

GET /api/v1/userinfo

Fetches the user profile from Zitadel's userinfo endpoint using a valid access token.

  • Description: Acts as a secure proxy to Zitadel's userinfo endpoint
  • Request:
    • Headers:
      HeaderDescription
      AuthorizationRequired. The bearer token. Must be in the format Bearer <token>
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON): The user profile information
      {
      "userinfo": {
      "sub": "1234567890",
      "name": "John Doe",
      "email": "john.doe@example.com",
      "email_verified": true
      }
      }
  • Response (Error):
    • HTTP 400 Bad Request: If the Authorization header is missing
    • HTTP 401 Unauthorized: If the access token is invalid or does not have the required scopes

πŸ“š References:

About

πŸ›‘οΈ Zitadel Authentication Abstraction

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

ZitAuth πŸ›‘οΈ ✨

ZitAuth is a centralized authentication gateway that transforms Zitadel integration from a headache into a breeze. One clean API for all your appsβ€”web, mobile, and backend services.

Why ZitAuth? Because your applications shouldn't care about JWT validation, JWKS endpoints, or OIDC flows. They should just work.

✨ Key Features

πŸ” Bulletproof User Authentication: OIDC login with PKCE flow
πŸ€– Effortless Service-to-Service Auth: M2M authentication with JWT Bearer Grant
βœ… One-Stop Token Validation: Single /validate endpoint handles all tokens
🎯 Ready-to-Run Examples: Complete user and machine authentication simulation
🐍 Dual Implementation: Available in both Python (FastAPI) and Node.js (Express)

πŸ“Š Architecture Diagram

graph TD
subgraph "Clients"
User[πŸ‘€ User]
M2MClient[πŸ’» Backend Service]
end
subgraph "Application Layer"
SPA[🌐 SPA / Web App]
ProtectedAPI[πŸ“¦ Your Protected API]
end
subgraph "Authentication Core"
ZitAuth[πŸ›‘οΈ ZitAuth Gateway]
Zitadel[πŸ” Zitadel IdP]
end
%% User Authentication Flow
User -- "Initiates Login" --> SPA
SPA -- "Redirects for Auth" --> ZitAuth
ZitAuth -- "Handles OIDC Flow" --> Zitadel
Zitadel -- "Authenticates & Issues Code" --> ZitAuth
ZitAuth -- "Exchanges Code for Token" --> Zitadel
ZitAuth -- "Returns Token" --> SPA
SPA -- "Calls API with User Token" --> ProtectedAPI
%% M2M Authentication Flow
M2MClient -- "Requests M2M Token" --> ZitAuth
ZitAuth -- "Handles JWT Bearer Grant" --> Zitadel
Zitadel -- "Issues M2M Token" --> ZitAuth
ZitAuth -- "Returns Token" --> M2MClient
M2MClient -- "Calls API with M2M Token" --> ProtectedAPI
%% Centralized Validation
ProtectedAPI -- "Validates Token via Gateway" --> ZitAuth
Loading

πŸš€ Quick Start

Prerequisites

  • Docker and Docker Compose
  • Python 3.11+
  • pip for installing dependencies

Step 1: Set Up the Zitadel Environment

  • The provided docker-compose.yaml file is used to set up a local Zitadel instance. You can also use Zitadel hosted on the cloud.

    docker compose up -d
  • You can access the Zitadel Console at http://localhost:8080.

Step 2: Configure Zitadel

  • After starting Zitadel, log in to the console at http://localhost:8080 using these creds:

    • username: zitadel-admin@zitadel.localhost
    • password: Password1!
  • You will need to create a project and application within it (for mobile login flow) and a service user (for m2m flow) and configure login policies (Required for User registration)

    Click to expand Zitadel Application Configuration
    • In your project, create a new application of type User Agent
    • Select authentication method as PKCE, toggle the Development mode to allow redirect to http
    • Configure the redirect URI as http://localhost:8000/api/v1/callback
    • After creating the application, Go to the Token Settings tab and select Auth Token Type as JWT
    • Go to the URLs tab and note down the urls and client id in .env file
    Click to expand Zitadel Service User Configuration
    • In the Zitadel console, go to Users Section and then to the Service Users tab
    • Click on the New button
    • Fill basic details and select the Access Token Type as JWT
    • Go to Keys tab and add a new key of type JSON and download it
    • Save this file to a secure location in your project. Provide the path to this file in the .env file
    Click to expand Zitadel Login Policy Configuration - Navigate to the `Default Settings` setion on the zitadel console - Go to the `External Links` tab in the `Other` subsection - Configure `Link to Terms of Service` and `Link to Privacy Policy` (or use any dummy links for demo) - Click `Save`

Step 3: Configure the ZitAuth Service

  1. Create the .env file by copying the example:

    cp .env.example .env
  2. Edit the .env file:

    • Fill the environment variables with the information received from the step before
  3. Install dependencies:

    pip install -r requirements.txt

πŸƒ Running the Services

The start.sh script is provided to run the main components. You can inspect the script to see the individual commands.

Start the main services:

# This will start ZitAuth on port 8000
uvicorn python.main:app --reload --port 8000

Note - For running in nodejs, refer to nodejs/README.md

πŸ› οΈ Testing

Testing the User Login Flow (SPA)

ZitAuth SPA setup

  1. Start the SPA app:

    uvicorn examples.spa_app.main:app --reload --port 3001
  2. Open your browser and navigate to the SPA at http://127.0.0.1:3001

  3. Click the "Login via ZitAuth" button. You will be redirected to the Zitadel login page

  4. Log in with a user or register one

  5. After a successful login, you will be redirected back to the SPA, and the status will show "Access token received"

  6. Click Call Protected Endpoint and Fetch User Info to test the authenticated API calls

Testing the Machine-to-Machine (M2M) Flow

  1. Ensure the main services (ZitAuth Gateway and SPA App) are running

  2. In a new terminal, run the M2M simulation script:

    python examples/m2m_sim.py
  3. Observe the logs. The script will request an M2M token, receive it, and use it to successfully call the protected API

πŸ—οΈ Project Structure:

.
β”œβ”€β”€ docker-compose.yaml # Sets up Zitadel server locally
β”œβ”€β”€ examples/
β”‚ β”œβ”€β”€ m2m_sim.py # Simulates the local service (M2M)
β”‚ └── spa_app/ # Simulates the mobile/web application
β”œβ”€β”€ python/
β”‚ β”œβ”€β”€ client.py # The core ZitadelClient abstraction layer
β”‚ β”œβ”€β”€ main.py # The FastAPI service (ZitAuth Gateway)
β”‚ └── utils.py # Helper functions
β”œβ”€β”€ .env.example # Template for environment variables
β”œβ”€β”€ requirements.txt # Python dependencies
└── start.sh # Helper script to run services

βš™οΈ API Documentation

Click to expand API Endpoint Documentation

GET /api/v1/login

Initiates the OIDC user login flow. This endpoint is intended to be used by a browser, which will be redirected.

  • Description: Starts the user authentication process by redirecting the user to the Zitadel login page
  • Request: No parameters or headers required
  • Response (Success):
    • HTTP 302 Found: A redirect to the Zitadel authorization endpoint
  • Response (Error):
    • HTTP 400 Bad Request: If there is an internal error generating the login URL

GET /api/v1/callback

Handles the OIDC callback from Zitadel after a user authenticates. This endpoint is used by the browser as part of the redirect flow.

  • Description: Zitadel redirects the user's browser to this endpoint after a successful login. The endpoint exchanges the received authorization code for an access token
  • Request:
    • Query Parameters:
      ParameterDescription
      codeThe authorization code issued by Zitadel
      stateThe unique state string used to prevent CSRF attacks
  • Response (Success):
    • HTTP 302 Found: Redirects the user's browser back to the SPA (SPA_ORIGIN), with the access_token included in the URL hash fragment
  • Response (Error):
    • HTTP 400 Bad Request: If the state is invalid, expired, or the token exchange fails

GET /api/v1/m2m-token

Issues a machine-to-machine (M2M) access token using a pre-configured service account.

  • Description: Allows a trusted backend service to acquire an access token by handling the JWT Bearer Grant flow on behalf of the service
  • Request: No parameters or headers required. The service authenticates itself by its ability to call this endpoint
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON):
      {
      "access_token": "ey..."
      }
  • Response (Error):
    • HTTP 500 Internal Server Error: If the service account file is misconfigured or Zitadel rejects the request

GET /api/v1/validate

Validates an access token and returns the authentication status.

  • Description: A centralized endpoint for any service to delegate token validation. It checks the token's signature against Zitadel's public keys using its JWKS endpoint
  • Request:
    • Headers:
      HeaderDescription
      AuthorizationRequired. The bearer token. Must be in the format Bearer <token>
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON): The decoded claims (payload) of the JWT
      {
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022,
      "exp": 1516242622,
      "iss": "http://localhost:8080"
      }
  • Response (Error):
    • HTTP 400 Bad Request: If the Authorization header is missing or malformed
    • HTTP 401 Unauthorized: If the token is invalid (expired, bad signature, etc.)

GET /api/v1/userinfo

Fetches the user profile from Zitadel's userinfo endpoint using a valid access token.

  • Description: Acts as a secure proxy to Zitadel's userinfo endpoint
  • Request:
    • Headers:
      HeaderDescription
      AuthorizationRequired. The bearer token. Must be in the format Bearer <token>
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON): The user profile information
      {
      "userinfo": {
      "sub": "1234567890",
      "name": "John Doe",
      "email": "john.doe@example.com",
      "email_verified": true
      }
      }
  • Response (Error):
    • HTTP 400 Bad Request: If the Authorization header is missing
    • HTTP 401 Unauthorized: If the access token is invalid or does not have the required scopes

πŸ“š References:

About

πŸ›‘οΈ Zitadel Authentication Abstraction

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

ZitAuth πŸ›‘οΈ ✨

ZitAuth is a centralized authentication gateway that transforms Zitadel integration from a headache into a breeze. One clean API for all your appsβ€”web, mobile, and backend services.

Why ZitAuth? Because your applications shouldn't care about JWT validation, JWKS endpoints, or OIDC flows. They should just work.

✨ Key Features

πŸ” Bulletproof User Authentication: OIDC login with PKCE flow
πŸ€– Effortless Service-to-Service Auth: M2M authentication with JWT Bearer Grant
βœ… One-Stop Token Validation: Single /validate endpoint handles all tokens
🎯 Ready-to-Run Examples: Complete user and machine authentication simulation
🐍 Dual Implementation: Available in both Python (FastAPI) and Node.js (Express)

πŸ“Š Architecture Diagram

graph TD
subgraph "Clients"
User[πŸ‘€ User]
M2MClient[πŸ’» Backend Service]
end
subgraph "Application Layer"
SPA[🌐 SPA / Web App]
ProtectedAPI[πŸ“¦ Your Protected API]
end
subgraph "Authentication Core"
ZitAuth[πŸ›‘οΈ ZitAuth Gateway]
Zitadel[πŸ” Zitadel IdP]
end
%% User Authentication Flow
User -- "Initiates Login" --> SPA
SPA -- "Redirects for Auth" --> ZitAuth
ZitAuth -- "Handles OIDC Flow" --> Zitadel
Zitadel -- "Authenticates & Issues Code" --> ZitAuth
ZitAuth -- "Exchanges Code for Token" --> Zitadel
ZitAuth -- "Returns Token" --> SPA
SPA -- "Calls API with User Token" --> ProtectedAPI
%% M2M Authentication Flow
M2MClient -- "Requests M2M Token" --> ZitAuth
ZitAuth -- "Handles JWT Bearer Grant" --> Zitadel
Zitadel -- "Issues M2M Token" --> ZitAuth
ZitAuth -- "Returns Token" --> M2MClient
M2MClient -- "Calls API with M2M Token" --> ProtectedAPI
%% Centralized Validation
ProtectedAPI -- "Validates Token via Gateway" --> ZitAuth
Loading

πŸš€ Quick Start

Prerequisites

  • Docker and Docker Compose
  • Python 3.11+
  • pip for installing dependencies

Step 1: Set Up the Zitadel Environment

  • The provided docker-compose.yaml file is used to set up a local Zitadel instance. You can also use Zitadel hosted on the cloud.

    docker compose up -d
  • You can access the Zitadel Console at http://localhost:8080.

Step 2: Configure Zitadel

  • After starting Zitadel, log in to the console at http://localhost:8080 using these creds:

    • username: zitadel-admin@zitadel.localhost
    • password: Password1!
  • You will need to create a project and application within it (for mobile login flow) and a service user (for m2m flow) and configure login policies (Required for User registration)

    Click to expand Zitadel Application Configuration
    • In your project, create a new application of type User Agent
    • Select authentication method as PKCE, toggle the Development mode to allow redirect to http
    • Configure the redirect URI as http://localhost:8000/api/v1/callback
    • After creating the application, Go to the Token Settings tab and select Auth Token Type as JWT
    • Go to the URLs tab and note down the urls and client id in .env file
    Click to expand Zitadel Service User Configuration
    • In the Zitadel console, go to Users Section and then to the Service Users tab
    • Click on the New button
    • Fill basic details and select the Access Token Type as JWT
    • Go to Keys tab and add a new key of type JSON and download it
    • Save this file to a secure location in your project. Provide the path to this file in the .env file
    Click to expand Zitadel Login Policy Configuration - Navigate to the `Default Settings` setion on the zitadel console - Go to the `External Links` tab in the `Other` subsection - Configure `Link to Terms of Service` and `Link to Privacy Policy` (or use any dummy links for demo) - Click `Save`

Step 3: Configure the ZitAuth Service

  1. Create the .env file by copying the example:

    cp .env.example .env
  2. Edit the .env file:

    • Fill the environment variables with the information received from the step before
  3. Install dependencies:

    pip install -r requirements.txt

πŸƒ Running the Services

The start.sh script is provided to run the main components. You can inspect the script to see the individual commands.

Start the main services:

# This will start ZitAuth on port 8000
uvicorn python.main:app --reload --port 8000

Note - For running in nodejs, refer to nodejs/README.md

πŸ› οΈ Testing

Testing the User Login Flow (SPA)

ZitAuth SPA setup

  1. Start the SPA app:

    uvicorn examples.spa_app.main:app --reload --port 3001
  2. Open your browser and navigate to the SPA at http://127.0.0.1:3001

  3. Click the "Login via ZitAuth" button. You will be redirected to the Zitadel login page

  4. Log in with a user or register one

  5. After a successful login, you will be redirected back to the SPA, and the status will show "Access token received"

  6. Click Call Protected Endpoint and Fetch User Info to test the authenticated API calls

Testing the Machine-to-Machine (M2M) Flow

  1. Ensure the main services (ZitAuth Gateway and SPA App) are running

  2. In a new terminal, run the M2M simulation script:

    python examples/m2m_sim.py
  3. Observe the logs. The script will request an M2M token, receive it, and use it to successfully call the protected API

πŸ—οΈ Project Structure:

.
β”œβ”€β”€ docker-compose.yaml # Sets up Zitadel server locally
β”œβ”€β”€ examples/
β”‚ β”œβ”€β”€ m2m_sim.py # Simulates the local service (M2M)
β”‚ └── spa_app/ # Simulates the mobile/web application
β”œβ”€β”€ python/
β”‚ β”œβ”€β”€ client.py # The core ZitadelClient abstraction layer
β”‚ β”œβ”€β”€ main.py # The FastAPI service (ZitAuth Gateway)
β”‚ └── utils.py # Helper functions
β”œβ”€β”€ .env.example # Template for environment variables
β”œβ”€β”€ requirements.txt # Python dependencies
└── start.sh # Helper script to run services

βš™οΈ API Documentation

Click to expand API Endpoint Documentation

GET /api/v1/login

Initiates the OIDC user login flow. This endpoint is intended to be used by a browser, which will be redirected.

  • Description: Starts the user authentication process by redirecting the user to the Zitadel login page
  • Request: No parameters or headers required
  • Response (Success):
    • HTTP 302 Found: A redirect to the Zitadel authorization endpoint
  • Response (Error):
    • HTTP 400 Bad Request: If there is an internal error generating the login URL

GET /api/v1/callback

Handles the OIDC callback from Zitadel after a user authenticates. This endpoint is used by the browser as part of the redirect flow.

  • Description: Zitadel redirects the user's browser to this endpoint after a successful login. The endpoint exchanges the received authorization code for an access token
  • Request:
    • Query Parameters:
      ParameterDescription
      codeThe authorization code issued by Zitadel
      stateThe unique state string used to prevent CSRF attacks
  • Response (Success):
    • HTTP 302 Found: Redirects the user's browser back to the SPA (SPA_ORIGIN), with the access_token included in the URL hash fragment
  • Response (Error):
    • HTTP 400 Bad Request: If the state is invalid, expired, or the token exchange fails

GET /api/v1/m2m-token

Issues a machine-to-machine (M2M) access token using a pre-configured service account.

  • Description: Allows a trusted backend service to acquire an access token by handling the JWT Bearer Grant flow on behalf of the service
  • Request: No parameters or headers required. The service authenticates itself by its ability to call this endpoint
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON):
      {
      "access_token": "ey..."
      }
  • Response (Error):
    • HTTP 500 Internal Server Error: If the service account file is misconfigured or Zitadel rejects the request

GET /api/v1/validate

Validates an access token and returns the authentication status.

  • Description: A centralized endpoint for any service to delegate token validation. It checks the token's signature against Zitadel's public keys using its JWKS endpoint
  • Request:
    • Headers:
      HeaderDescription
      AuthorizationRequired. The bearer token. Must be in the format Bearer <token>
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON): The decoded claims (payload) of the JWT
      {
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022,
      "exp": 1516242622,
      "iss": "http://localhost:8080"
      }
  • Response (Error):
    • HTTP 400 Bad Request: If the Authorization header is missing or malformed
    • HTTP 401 Unauthorized: If the token is invalid (expired, bad signature, etc.)

GET /api/v1/userinfo

Fetches the user profile from Zitadel's userinfo endpoint using a valid access token.

  • Description: Acts as a secure proxy to Zitadel's userinfo endpoint
  • Request:
    • Headers:
      HeaderDescription
      AuthorizationRequired. The bearer token. Must be in the format Bearer <token>
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON): The user profile information
      {
      "userinfo": {
      "sub": "1234567890",
      "name": "John Doe",
      "email": "john.doe@example.com",
      "email_verified": true
      }
      }
  • Response (Error):
    • HTTP 400 Bad Request: If the Authorization header is missing
    • HTTP 401 Unauthorized: If the access token is invalid or does not have the required scopes

πŸ“š References:

About

πŸ›‘οΈ Zitadel Authentication Abstraction

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

ZitAuth πŸ›‘οΈ ✨

ZitAuth is a centralized authentication gateway that transforms Zitadel integration from a headache into a breeze. One clean API for all your appsβ€”web, mobile, and backend services.

Why ZitAuth? Because your applications shouldn't care about JWT validation, JWKS endpoints, or OIDC flows. They should just work.

✨ Key Features

πŸ” Bulletproof User Authentication: OIDC login with PKCE flow
πŸ€– Effortless Service-to-Service Auth: M2M authentication with JWT Bearer Grant
βœ… One-Stop Token Validation: Single /validate endpoint handles all tokens
🎯 Ready-to-Run Examples: Complete user and machine authentication simulation
🐍 Dual Implementation: Available in both Python (FastAPI) and Node.js (Express)

πŸ“Š Architecture Diagram

graph TD
subgraph "Clients"
User[πŸ‘€ User]
M2MClient[πŸ’» Backend Service]
end
subgraph "Application Layer"
SPA[🌐 SPA / Web App]
ProtectedAPI[πŸ“¦ Your Protected API]
end
subgraph "Authentication Core"
ZitAuth[πŸ›‘οΈ ZitAuth Gateway]
Zitadel[πŸ” Zitadel IdP]
end
%% User Authentication Flow
User -- "Initiates Login" --> SPA
SPA -- "Redirects for Auth" --> ZitAuth
ZitAuth -- "Handles OIDC Flow" --> Zitadel
Zitadel -- "Authenticates & Issues Code" --> ZitAuth
ZitAuth -- "Exchanges Code for Token" --> Zitadel
ZitAuth -- "Returns Token" --> SPA
SPA -- "Calls API with User Token" --> ProtectedAPI
%% M2M Authentication Flow
M2MClient -- "Requests M2M Token" --> ZitAuth
ZitAuth -- "Handles JWT Bearer Grant" --> Zitadel
Zitadel -- "Issues M2M Token" --> ZitAuth
ZitAuth -- "Returns Token" --> M2MClient
M2MClient -- "Calls API with M2M Token" --> ProtectedAPI
%% Centralized Validation
ProtectedAPI -- "Validates Token via Gateway" --> ZitAuth
Loading

πŸš€ Quick Start

Prerequisites

  • Docker and Docker Compose
  • Python 3.11+
  • pip for installing dependencies

Step 1: Set Up the Zitadel Environment

  • The provided docker-compose.yaml file is used to set up a local Zitadel instance. You can also use Zitadel hosted on the cloud.

    docker compose up -d
  • You can access the Zitadel Console at http://localhost:8080.

Step 2: Configure Zitadel

  • After starting Zitadel, log in to the console at http://localhost:8080 using these creds:

    • username: zitadel-admin@zitadel.localhost
    • password: Password1!
  • You will need to create a project and application within it (for mobile login flow) and a service user (for m2m flow) and configure login policies (Required for User registration)

    Click to expand Zitadel Application Configuration
    • In your project, create a new application of type User Agent
    • Select authentication method as PKCE, toggle the Development mode to allow redirect to http
    • Configure the redirect URI as http://localhost:8000/api/v1/callback
    • After creating the application, Go to the Token Settings tab and select Auth Token Type as JWT
    • Go to the URLs tab and note down the urls and client id in .env file
    Click to expand Zitadel Service User Configuration
    • In the Zitadel console, go to Users Section and then to the Service Users tab
    • Click on the New button
    • Fill basic details and select the Access Token Type as JWT
    • Go to Keys tab and add a new key of type JSON and download it
    • Save this file to a secure location in your project. Provide the path to this file in the .env file
    Click to expand Zitadel Login Policy Configuration - Navigate to the `Default Settings` setion on the zitadel console - Go to the `External Links` tab in the `Other` subsection - Configure `Link to Terms of Service` and `Link to Privacy Policy` (or use any dummy links for demo) - Click `Save`

Step 3: Configure the ZitAuth Service

  1. Create the .env file by copying the example:

    cp .env.example .env
  2. Edit the .env file:

    • Fill the environment variables with the information received from the step before
  3. Install dependencies:

    pip install -r requirements.txt

πŸƒ Running the Services

The start.sh script is provided to run the main components. You can inspect the script to see the individual commands.

Start the main services:

# This will start ZitAuth on port 8000
uvicorn python.main:app --reload --port 8000

Note - For running in nodejs, refer to nodejs/README.md

πŸ› οΈ Testing

Testing the User Login Flow (SPA)

ZitAuth SPA setup

  1. Start the SPA app:

    uvicorn examples.spa_app.main:app --reload --port 3001
  2. Open your browser and navigate to the SPA at http://127.0.0.1:3001

  3. Click the "Login via ZitAuth" button. You will be redirected to the Zitadel login page

  4. Log in with a user or register one

  5. After a successful login, you will be redirected back to the SPA, and the status will show "Access token received"

  6. Click Call Protected Endpoint and Fetch User Info to test the authenticated API calls

Testing the Machine-to-Machine (M2M) Flow

  1. Ensure the main services (ZitAuth Gateway and SPA App) are running

  2. In a new terminal, run the M2M simulation script:

    python examples/m2m_sim.py
  3. Observe the logs. The script will request an M2M token, receive it, and use it to successfully call the protected API

πŸ—οΈ Project Structure:

.
β”œβ”€β”€ docker-compose.yaml # Sets up Zitadel server locally
β”œβ”€β”€ examples/
β”‚ β”œβ”€β”€ m2m_sim.py # Simulates the local service (M2M)
β”‚ └── spa_app/ # Simulates the mobile/web application
β”œβ”€β”€ python/
β”‚ β”œβ”€β”€ client.py # The core ZitadelClient abstraction layer
β”‚ β”œβ”€β”€ main.py # The FastAPI service (ZitAuth Gateway)
β”‚ └── utils.py # Helper functions
β”œβ”€β”€ .env.example # Template for environment variables
β”œβ”€β”€ requirements.txt # Python dependencies
└── start.sh # Helper script to run services

βš™οΈ API Documentation

Click to expand API Endpoint Documentation

GET /api/v1/login

Initiates the OIDC user login flow. This endpoint is intended to be used by a browser, which will be redirected.

  • Description: Starts the user authentication process by redirecting the user to the Zitadel login page
  • Request: No parameters or headers required
  • Response (Success):
    • HTTP 302 Found: A redirect to the Zitadel authorization endpoint
  • Response (Error):
    • HTTP 400 Bad Request: If there is an internal error generating the login URL

GET /api/v1/callback

Handles the OIDC callback from Zitadel after a user authenticates. This endpoint is used by the browser as part of the redirect flow.

  • Description: Zitadel redirects the user's browser to this endpoint after a successful login. The endpoint exchanges the received authorization code for an access token
  • Request:
    • Query Parameters:
      ParameterDescription
      codeThe authorization code issued by Zitadel
      stateThe unique state string used to prevent CSRF attacks
  • Response (Success):
    • HTTP 302 Found: Redirects the user's browser back to the SPA (SPA_ORIGIN), with the access_token included in the URL hash fragment
  • Response (Error):
    • HTTP 400 Bad Request: If the state is invalid, expired, or the token exchange fails

GET /api/v1/m2m-token

Issues a machine-to-machine (M2M) access token using a pre-configured service account.

  • Description: Allows a trusted backend service to acquire an access token by handling the JWT Bearer Grant flow on behalf of the service
  • Request: No parameters or headers required. The service authenticates itself by its ability to call this endpoint
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON):
      {
      "access_token": "ey..."
      }
  • Response (Error):
    • HTTP 500 Internal Server Error: If the service account file is misconfigured or Zitadel rejects the request

GET /api/v1/validate

Validates an access token and returns the authentication status.

  • Description: A centralized endpoint for any service to delegate token validation. It checks the token's signature against Zitadel's public keys using its JWKS endpoint
  • Request:
    • Headers:
      HeaderDescription
      AuthorizationRequired. The bearer token. Must be in the format Bearer <token>
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON): The decoded claims (payload) of the JWT
      {
      "sub": "1234567890",
      "name": "John Doe",
      "iat": 1516239022,
      "exp": 1516242622,
      "iss": "http://localhost:8080"
      }
  • Response (Error):
    • HTTP 400 Bad Request: If the Authorization header is missing or malformed
    • HTTP 401 Unauthorized: If the token is invalid (expired, bad signature, etc.)

GET /api/v1/userinfo

Fetches the user profile from Zitadel's userinfo endpoint using a valid access token.

  • Description: Acts as a secure proxy to Zitadel's userinfo endpoint
  • Request:
    • Headers:
      HeaderDescription
      AuthorizationRequired. The bearer token. Must be in the format Bearer <token>
  • Response (Success):
    • HTTP 200 OK
    • Body (JSON): The user profile information
      {
      "userinfo": {
      "sub": "1234567890",
      "name": "John Doe",
      "email": "john.doe@example.com",
      "email_verified": true
      }
      }
  • Response (Error):
    • HTTP 400 Bad Request: If the Authorization header is missing
    • HTTP 401 Unauthorized: If the access token is invalid or does not have the required scopes

πŸ“š References:

About

πŸ›‘οΈ Zitadel Authentication Abstraction

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Used by

Contributors

Languages