mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-24 08:12:15 +00:00
docs: introduce versioned docs and migrate to fuma (#11166)
## Todos for release - [x] Configure Env in docs project on vercel - [x] Configure Root Path in the docs project on vercel - [ ] Remove old CSP https://github.com/zitadel/website/pull/1592 ## What we did This pull request migrates the project documentation from the old `docs/` directory to the new `apps/docs/` directory, introduces a new documentation system built with Next.js and Fumadocs, and updates all relevant references, configuration files, and documentation to reflect this change. It also adds new configuration and ignore files for the new documentation app, updates CI and linting to exclude the new docs from certain checks, and revises the contributing guidelines accordingly. **Documentation System Migration and New Docs App** * Migrated all documentation from `docs/` to `apps/docs/`, and updated all references in `README.md`, `CONTRIBUTING.md`, and other files to point to the new location. [[1]](diffhunk://#diff-eca12c0a30e25b4b46522ebf89465a03ba72a03f540796c979137931d8f92055L585-L640) [[2]](diffhunk://#diff-eca12c0a30e25b4b46522ebf89465a03ba72a03f540796c979137931d8f92055L660-R607) [[3]](diffhunk://#diff-eca12c0a30e25b4b46522ebf89465a03ba72a03f540796c979137931d8f92055L740-R687) [[4]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L2-R3) [[5]](diffhunk://#diff-b335630551682c19a781afebcf4d07bf978fb1f8ac04c6bf87428ed5106870f5L30-R30) * Added a new Next.js/Fumadocs-based documentation app under `apps/docs/`, including core app files, layouts, routing, search API, and a comprehensive `README.md` with development and contribution instructions. [[1]](diffhunk://#diff-5a1b07344a2c1b4d3f37b23ff1388b62cd9f57dea3c1cd23d8a0412b7602b132R1-R74) [[2]](diffhunk://#diff-462b9ad1eabbb7d1c29bb9c36e4931eb180fd7190900e6d2babf8f4d66ad1c28R1-R39) [[3]](diffhunk://#diff-e16ae25660ded787b10ac35dea96d5ecaacf895dae0afc8a9bd4382dc79a8c87R1-R7) [apps/docs/app/[[...slug]]/layout.tsxR1-R81](diffhunk://#diff-59e08acde4e805b7aeccef1dcf98f1d71dfc550777e6b9402085cee0e9fa4e0aR1-R81), [apps/docs/app/[[...slug]]/page.tsxR1-R79](diffhunk://#diff-e5df3f80d0fa01e12d63d81f29c57a9d14e846c78fd3beabb2ef768e38fd9580R1-R79), [[4]](diffhunk://#diff-389b34918e040cacaa87cd7201ffa462cc2b0b716736f537e3d3c660ac69353bR1-R7) [[5]](diffhunk://#diff-d3b03416d1c457b19f1c27b26f2db741412df841b875c26ccadc36e4522247f4R1-R29) [[6]](diffhunk://#diff-c8fb8339570a5305809be7c618e14705fd86390dc278e6ce8ba224a7bc8b0c3cR1-R25) **Configuration and Tooling Updates** * Updated `.github/workflows/codeql.yml`, `.golangci.yaml`, and `.github/dependabot.yml` to properly handle the new docs app: excluded `apps/docs` from certain checks, added npm dependency updates for the docs app, and excluded generated content. [[1]](diffhunk://#diff-12783128521e452af0cfac94b99b8d250413c516ec71fe6d97dbea666ff7ba27L8-R14) [[2]](diffhunk://#diff-9917ddc9f1c3304218f7269265b746d997c5c0615478177b5fceecd33ef47cb5R5-R6) [[3]](diffhunk://#diff-9917ddc9f1c3304218f7269265b746d997c5c0615478177b5fceecd33ef47cb5R126-R129) [[4]](diffhunk://#diff-dd4fbda47e51f1e35defb9275a9cd9c212ecde0b870cba89ddaaae65c5f3cd28R89-R106) * Updated `.devcontainer/devcontainer.json` to use the latest Go 1.25.3 version for consistency. **Licensing and Miscellaneous** * Added `apps/docs/` to the list of licensed directories in `LICENSING.md`. These changes ensure the documentation is now maintained in a modern, scalable system and all project tooling is updated to support the new structure. --------- Co-authored-by: Federico Coppede <[email protected]>
This commit is contained in:
co-authored by
Federico Coppede
parent
7b6395c348
commit
d8ea041c56
@@ -0,0 +1,75 @@
|
||||
---
|
||||
title: OAuth 2.0 Proxy
|
||||
---
|
||||
|
||||
[OAuth2-proxy](https://github.com/oauth2-proxy/oauth2-proxy) is a project which allows services to delegate the authentication flow to a IDP, for example **ZITADEL**
|
||||
|
||||
## Configure ZITADEL
|
||||
|
||||
### Setup Application and get Keys
|
||||
|
||||
Before we can start building our application we have do do a few configuration steps in ZITADEL Console.
|
||||
You will need to provide some information about your app. We recommend creating a new app to start from scratch. Navigate to your project and add a new application at the top of the page.
|
||||
Select Web Application and continue.
|
||||
We recommend that you use [Authorization Code](/apis/openidoauth/grant-types#authorization-code) for the OAuth 2.0 Proxy.
|
||||
|
||||
> Make sure Authentication Method is set to `BASIC` and the Application Type is set to `Web`.
|
||||
|
||||
### Redirect URLs
|
||||
|
||||
A redirect URL is a URL in your application where ZITADEL redirects the user after they have authenticated. Set your url to the domain the proxy will be deployed to or use the default one `http://127.0.0.1:4180/oauth2/callback`.
|
||||
|
||||
> If you are following along with the sample project you downloaded from our templates, you should set the Allowed Callback URL to `http://localhost:4200/auth/callback`. You will also have to set dev mode to `true` as this will enable unsecure http for the moment.
|
||||
|
||||
If you want to redirect the users back to a route on your application after they have logged out, add an optional redirect in the post redirectURI field.
|
||||
|
||||
Continue and Create the application.
|
||||
|
||||
### Client ID and Secret
|
||||
|
||||
After successful app creation a popup will appear showing you your clientID as well as a secret.
|
||||
Copy your client ID and Secrets as it will be needed in the next step.
|
||||
|
||||
> Note: You will be able to regenerate the secret at a later time if you lose it.
|
||||
|
||||
## OAuth 2.0 Proxy Setup
|
||||
|
||||
### Authentication Example
|
||||
|
||||
```toml
|
||||
provider = "oidc"
|
||||
user_id_claim = "sub" #uses the subject as ID instead of the email
|
||||
provider_display_name = "ZITADEL"
|
||||
redirect_url = "http://127.0.0.1:4180/oauth2/callback"
|
||||
oidc_issuer_url = "https://$CUSTOM_DOMAIN"
|
||||
upstreams = [
|
||||
"https://example.corp.com"
|
||||
]
|
||||
email_domains = [
|
||||
"*"
|
||||
]
|
||||
client_id = "{ZITADEL_GENERATED_CLIENT_ID}"
|
||||
client_secret = "{ZITADEL_GENERATED_CLIENT_SECRET}"
|
||||
pass_access_token = true
|
||||
cookie_secret = "{SUPPLY_SOME_SECRET_HERE}"
|
||||
skip_provider_button = true
|
||||
cookie_secure = false #localdev only false
|
||||
http_address = "127.0.0.1:4180" #localdev only
|
||||
```
|
||||
|
||||
> This was tested with version `oauth2-proxy v7.4.0 (built with go1.20.0)`
|
||||
|
||||
### Check for groups
|
||||
|
||||
If you want oauth2-proxy to check for roles in the tokens you have to add an [action](/guides/manage/console/actions-overview) in ZITADEL to [complement the token](/guides/manage/console/actions-overview) in ZITADEL to [complement the token](/apis/actions/complement-token) according to [this example](/guides/manage/console/actions-overview) in ZITADEL to [complement the token](/apis/actions/complement-token) according to [this example](https://github.com/zitadel/actions/blob/main/examples/custom_roles.js) and add the following configuration to the config:
|
||||
|
||||
```toml
|
||||
oidc_groups_claim = "{your_actions_group_key}"
|
||||
allowed_groups = ["list", "of", "allowed", "roles"]
|
||||
```
|
||||
|
||||
## Completion
|
||||
|
||||
You have successfully integrated ZITADEL in your proxy!
|
||||
|
||||
### What next?
|
||||
@@ -0,0 +1,53 @@
|
||||
1. Go to your Project and click on the **New** button as shown below.
|
||||
|
||||

|
||||
|
||||
2. Give a name to your application (Test API is the name given below) and select type **API**.
|
||||
|
||||

|
||||
|
||||
3. Select **JWT** as the authentication method and click **Continue**.
|
||||
|
||||

|
||||
|
||||
4. Now review your configuration and click **Create**.
|
||||
|
||||

|
||||
|
||||
5. You will now see the API’s **Client ID**. You will not see a Client Secret because we are using a private JWT key.
|
||||
|
||||

|
||||
|
||||
6. Next, we must create the key pairs. Click on **New**.
|
||||
|
||||

|
||||
|
||||
7. Select **JSON** as the type of key. You can also set an expiration time for the key or leave it empty. Click on **Add**.
|
||||
|
||||

|
||||
|
||||
8. Download the created key by clicking the **Download** button and then click **Close**.
|
||||
|
||||

|
||||
|
||||
9. The key will be downloaded.
|
||||
|
||||

|
||||
|
||||
10. When you click on URLs on the left, you will see the relevant OIDC URLs. Note down the **issuer** URL, **token_endpoint** and **introspection_endpoint**.
|
||||
|
||||

|
||||
|
||||
11. The key that you downloaded will be of the following format.
|
||||
```
|
||||
{
|
||||
"type":"application",
|
||||
"keyId":"<YOUR_KEY_ID>",
|
||||
"key":"-----BEGIN RSA PRIVATE KEY-----\<YOUR_PRIVATE_KEY>\n-----END RSA PRIVATE KEY-----\n",
|
||||
"appId":"<YOUR_APP_ID>",
|
||||
"clientId":"<YOUR_CLIENT_ID>"
|
||||
}
|
||||
```
|
||||
12. Also note down the **Resource ID** of your project.
|
||||
|
||||

|
||||
@@ -0,0 +1,42 @@
|
||||
1. Go to the **Users** tab in your organization as shown below and click on the **Service Users** tab.
|
||||
|
||||

|
||||
|
||||
2. To add a service user, click on the **New** button.
|
||||
|
||||

|
||||
|
||||
3. Next, add the details of the service user and select either **Bearer** or **JWT** for **Access Token Type** and click on **Create**. For this example, we will select **JWT**.
|
||||
|
||||

|
||||
|
||||
4. Now you will see the saved details.
|
||||
|
||||

|
||||
|
||||
5. Next, we need to generate a private-public key pair in ZITADEL and you must get the private key to sign your JWT. Go to **Keys** and click on **New**.
|
||||
|
||||

|
||||
|
||||
6. Select type **JSON** and click **Add**.
|
||||
|
||||

|
||||
|
||||
7. Download the key by clicking **Download**. After the download, click **Close**.
|
||||
|
||||

|
||||
|
||||
8. You will see the following screen afterwards.
|
||||
|
||||

|
||||
|
||||
9. The downloaded key will be of the following format:
|
||||
|
||||
```
|
||||
{
|
||||
"type":"serviceaccount",
|
||||
"keyId":"<YOUR_KEY_ID>",
|
||||
"key":"-----BEGIN RSA PRIVATE KEY-----\n<YOUR_KEY>\n-----END RSA PRIVATE KEY-----\n",
|
||||
"userId":"<YOUR_USER_ID>"
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,36 @@
|
||||
In order to access this route, you must create the role `read:messages` in your ZITADEL project and also create an authorization for the service user you created by adding the role to the user. Follow these steps to do so:
|
||||
|
||||
1. Go to your project and select **Roles**. Click **New**.
|
||||
|
||||

|
||||
|
||||
2. Add the `read:messages` role as shown below and click **Save**.
|
||||
|
||||

|
||||
|
||||
3. You will see the created role listed.
|
||||
|
||||

|
||||
|
||||
4. To assign this role to a user, click on **Authorizations**.
|
||||
|
||||

|
||||
|
||||
5. Select the user you want to assign the role to.
|
||||
|
||||

|
||||
|
||||
6. Select the project where this authorization is applicable.
|
||||
|
||||

|
||||
7. Click **Continue**.
|
||||
|
||||

|
||||
|
||||
8. Select the role **read:messages** and click **Save**.
|
||||
|
||||

|
||||
|
||||
9. You will now see the your service user has been assigned the role **read:messages**.
|
||||
|
||||

|
||||
@@ -0,0 +1,9 @@
|
||||
To install Django:
|
||||
```bash
|
||||
python -m pip install Django
|
||||
```
|
||||
|
||||
Then in your folder of choice call the following command to create a Django base:
|
||||
```bash
|
||||
django-admin startproject mysite .
|
||||
```
|
||||
@@ -0,0 +1,5 @@
|
||||
As we use local environmental variables please install dotenv:
|
||||
|
||||
```bash
|
||||
python -m pip install python-dotenv
|
||||
```
|
||||
@@ -0,0 +1 @@
|
||||
You have to install Python as described in [their documentation](https://wiki.python.org/moin/BeginnersGuide/Download).
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
title: "APIs / Backend Quickstart Guides"
|
||||
description: "Quickstart guides for integrating ZITADEL authentication into APIs / Backend Services."
|
||||
---
|
||||
|
||||
{/* THIS FILE IS AUTO-GENERATED FROM SIDEBAR-DATA.
|
||||
ANY MANUAL CHANGES WILL BE OVERWRITTEN.
|
||||
*/}
|
||||
|
||||
import { Card, Cards } from 'fumadocs-ui/components/card';
|
||||
import { FileText, Folder, Link as LinkIcon } from 'lucide-react';
|
||||
|
||||
<Cards>
|
||||
<Card title="Go" href="/examples/secure-api/go" icon={<FileText />} />
|
||||
<Card title="Java Spring" href="/examples/secure-api/java-spring" icon={<FileText />} />
|
||||
<Card title="Python Django" href="/examples/secure-api/python-django" icon={<FileText />} />
|
||||
<Card title="Python Flask" href="/examples/secure-api/python-flask" icon={<FileText />} />
|
||||
<Card title="Nodejs Nestjs" href="/examples/secure-api/nodejs-nestjs" icon={<FileText />} />
|
||||
<Card title="Pylon" href="/examples/secure-api/pylon" icon={<FileText />} />
|
||||
</Cards>
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
title: "Frontend (SPA) Quickstart Guides"
|
||||
description: "Quickstart guides for integrating ZITADEL authentication into frontend single-page applications."
|
||||
---
|
||||
|
||||
{/* THIS FILE IS AUTO-GENERATED FROM SIDEBAR-DATA.
|
||||
ANY MANUAL CHANGES WILL BE OVERWRITTEN.
|
||||
*/}
|
||||
|
||||
import { Card, Cards } from 'fumadocs-ui/components/card';
|
||||
import { FileText, Folder, Link as LinkIcon } from 'lucide-react';
|
||||
|
||||
<Cards>
|
||||
<Card title="Vanilla-JS" href="https://github.com/zitadel/zitadel-vanilla-js" icon={<LinkIcon />} external />
|
||||
<Card title="React" href="/examples/login/react" icon={<FileText />} />
|
||||
<Card title="Angular" href="/examples/login/angular" icon={<FileText />} />
|
||||
<Card title="Vue" href="/examples/login/vue" icon={<FileText />} />
|
||||
</Cards>
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
title: "Full-Stack / SSR Quickstart Guides"
|
||||
description: "Quickstart guides for integrating ZITADEL authentication into Full-Stack / SSR applications."
|
||||
---
|
||||
|
||||
{/* THIS FILE IS AUTO-GENERATED FROM SIDEBAR-DATA.
|
||||
ANY MANUAL CHANGES WILL BE OVERWRITTEN.
|
||||
*/}
|
||||
|
||||
import { Card, Cards } from 'fumadocs-ui/components/card';
|
||||
import { FileText, Folder, Link as LinkIcon } from 'lucide-react';
|
||||
|
||||
<Cards>
|
||||
<Card title="Nextjs" href="/examples/login/nextjs" icon={<FileText />} />
|
||||
<Card title="Nextjs B2b" href="/examples/login/nextjs-b2b" icon={<FileText />} />
|
||||
</Cards>
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
title: "Example Applications"
|
||||
description: "Practical examples showing how to integrate ZITADEL authentication and secure APIs across different application types and frameworks."
|
||||
---
|
||||
|
||||
{/* THIS FILE IS AUTO-GENERATED FROM SIDEBAR-DATA.
|
||||
ANY MANUAL CHANGES WILL BE OVERWRITTEN.
|
||||
*/}
|
||||
|
||||
import { Card, Cards } from 'fumadocs-ui/components/card';
|
||||
import { FileText, Folder, Link as LinkIcon } from 'lucide-react';
|
||||
|
||||
<Cards>
|
||||
<Card title="Frontend (SPA)" href="/examples/introduction/frontend" icon={<Folder />} />
|
||||
<Card title="Mobile & Native" href="/examples/introduction/mobile" icon={<Folder />} />
|
||||
<Card title="Full-Stack / SSR" href="/examples/introduction/fullstack" icon={<Folder />} />
|
||||
<Card title="Web App (Server-Side)" href="/examples/introduction/webapp" icon={<Folder />} />
|
||||
<Card title="APIs / Backend Services" href="/examples/introduction/backend" icon={<Folder />} />
|
||||
</Cards>
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
title: "Mobile & Native Quickstart Guides"
|
||||
description: "Quickstart guides for integrating ZITADEL authentication into Mobile & Native applications."
|
||||
---
|
||||
|
||||
{/* THIS FILE IS AUTO-GENERATED FROM SIDEBAR-DATA.
|
||||
ANY MANUAL CHANGES WILL BE OVERWRITTEN.
|
||||
*/}
|
||||
|
||||
import { Card, Cards } from 'fumadocs-ui/components/card';
|
||||
import { FileText, Folder, Link as LinkIcon } from 'lucide-react';
|
||||
|
||||
<Cards>
|
||||
<Card title="Flutter" href="/examples/login/flutter" icon={<FileText />} />
|
||||
</Cards>
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
title: "Web App (Server-Side) Quickstart Guides"
|
||||
description: "Quickstart guides for integrating ZITADEL authentication into Web App (Server-Side) applications."
|
||||
---
|
||||
|
||||
{/* THIS FILE IS AUTO-GENERATED FROM SIDEBAR-DATA.
|
||||
ANY MANUAL CHANGES WILL BE OVERWRITTEN.
|
||||
*/}
|
||||
|
||||
import { Card, Cards } from 'fumadocs-ui/components/card';
|
||||
import { FileText, Folder, Link as LinkIcon } from 'lucide-react';
|
||||
|
||||
<Cards>
|
||||
<Card title="Symfony" href="/examples/login/symfony" icon={<FileText />} />
|
||||
<Card title="Java Spring" href="/examples/login/java-spring" icon={<FileText />} />
|
||||
<Card title="Python Django" href="/examples/login/python-django" icon={<FileText />} />
|
||||
<Card title="Go" href="/examples/login/go" icon={<FileText />} />
|
||||
</Cards>
|
||||
@@ -0,0 +1,170 @@
|
||||
---
|
||||
title: ZITADEL with Angular
|
||||
sidebar_label: Angular
|
||||
---
|
||||
|
||||
This integration guide demonstrates the recommended way to incorporate ZITADEL into your Angular application.
|
||||
It explains how to enable user login in your application and how to fetch data from the user info endpoint.
|
||||
|
||||
By the end of this guide, your application will have login functionality and will be able to access the current user's profile.
|
||||
|
||||
> This documentation references our [example](https://github.com/zitadel/zitadel-angular) on GitHub. Please note that we wrote the ZITADEL Management Console in Angular, so you can also use that as a reference.
|
||||
|
||||
## Set up application and obtain keys
|
||||
|
||||
Before we begin developing our application, we need to perform a few configuration steps in the ZITADEL Console.
|
||||
You'll need to provide some information about your app. We recommend creating a new app to start from scratch. Navigate to your Project, then add a new application at the top of the page.
|
||||
Select the **User Agent** application type and continue.
|
||||
We recommend that you use [Proof Key for Code Exchange (PKCE)](/apis/openidoauth/grant-types#proof-key-for-code-exchange) for all SPA applications.
|
||||
|
||||

|
||||
|
||||
### Redirect URIs
|
||||
|
||||
The Redirect URIs field tells ZITADEL where it's allowed to redirect users after authentication. For development, you can set dev mode to `true` to enable insecure HTTP and redirect to a `localhost` URI.
|
||||
The Post-logout redirect send the users back to a route on your application after they have logged out.
|
||||
|
||||
> If you are following along with the [example](https://github.com/zitadel/zitadel-angular), set the dev mode to `true`, the Redirect URIs to `http://localhost:4200/auth/callback` and Post redirect URI to `http://localhost:4200/signedout`.
|
||||
|
||||
Continue and create the application.
|
||||
|
||||
### Client ID
|
||||
|
||||
After successful creation of the app, a pop-up will appear displaying the app's client ID. Copy the client ID, as you will need it to configure your Angular client.
|
||||
|
||||
## Angular setup
|
||||
|
||||
Now that you have configured your web application on the ZITADEL side, you can proceed with the integration of your Angular client.
|
||||
|
||||
### Install Angular dependencies
|
||||
|
||||
To connect with ZITADEL, you need to install an OAuth/OIDC client. Run the following command:
|
||||
|
||||
```bash
|
||||
npm install angular-oauth2-oidc
|
||||
```
|
||||
|
||||
### Create and configure the auth module
|
||||
|
||||
Add _OAuthModule_ to your Angular imports in _AppModule_ and provide the _AuthConfig_ in the providers' section. Also, ensure that you import the _HTTPClientModule_.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-angular/blob/main/src/app/app.module.ts
|
||||
```
|
||||
|
||||
Set _openid_, _profile_ and _email_ as scope, _code_ as responseType, and oidc to _true_. Then create an authentication service to provide the functions to authenticate your user.
|
||||
|
||||
You can use Angular’s schematics to do so:
|
||||
|
||||
```bash
|
||||
ng g service services/authentication
|
||||
```
|
||||
|
||||
Copy the following code to your service. This code provides a function `authenticate()`, which redirects the user to ZITADEL. After a successful login, ZITADEL redirects the user back to the redirect URI configured in _AuthModule_ and ZITADEL Console. Ensure that both correspond, otherwise ZITADEL will throw an error.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-angular/blob/main/src/app/services/authentication.service.ts
|
||||
```
|
||||
|
||||
Our example includes a _StatehandlerService_ that redirects the user back to the route from which they initially came.If you don't need such behavior, you can omit the following line from the `authenticate()` method above.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-angular/blob/main/src/app/services/authentication.service.ts#L45
|
||||
```
|
||||
If you decide to use the _StatehandlerService_, include it in the `app.module`. Ensure it gets initialized first using Angular’s `APP_INITIALIZER`. You can find the service implementation in the [example](https://github.com/zitadel/zitadel-angular).
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-angular/blob/main/src/app/app.module.ts#L26-L30
|
||||
```
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-angular/blob/main/src/app/app.module.ts#L55-L78
|
||||
```
|
||||
|
||||
### Add login to your application
|
||||
|
||||
To log in a user, you need a component or a guard.
|
||||
|
||||
- A component could provide a button that initiates the login flow when clicked.
|
||||
- A guard initiates a login flow when a user without a stored valid access token attempts to access a protected route.
|
||||
|
||||
The use of these components depends heavily on your application. In most cases, you need both.
|
||||
|
||||
Generate a component like this:
|
||||
|
||||
```bash
|
||||
ng g component components/login
|
||||
```
|
||||
|
||||
Inject the _AuthenticationService_ and call `authenticate()` on some click event.
|
||||
|
||||
Do the same for the guard:
|
||||
```bash
|
||||
ng g guard guards/auth
|
||||
```
|
||||
|
||||
This code shows the _AuthGuard_ used in ZITADEL Console.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-angular/blob/main/src/app/guards/auth.guard.ts
|
||||
```
|
||||
|
||||
Add the guard to your _RouterModule_ similar to this:
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-angular/blob/main/src/app/app-routing.module.ts#L9-L31
|
||||
```
|
||||
|
||||
> Note: Make sure you redirect the user from your callback URL to a guarded page, so the `authenticate()` method is called again, and the access token is stored.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-angular/blob/main/src/app/app-routing.module.ts#L19-L21
|
||||
```
|
||||
|
||||
### Add logout to your application
|
||||
|
||||
Call `auth.signout()` to log out the current user. Keep in mind that you can also configure a logout redirect URI if you want your users to be redirected after logout.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-angular/blob/main/src/app/components/user/user.component.ts#L20-L22
|
||||
```
|
||||
|
||||
### Display user information
|
||||
|
||||
To fetch user data, you need to call the ZITADEL's user info endpoint. This data contains sensitive information and artifacts related to the current user's identity and the scopes you defined in your _AuthConfig_.
|
||||
Our _AuthenticationService_ already includes a method called _getOIDCUser()_. You can call it wherever you need this information.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-angular/blob/main/src/app/components/user/user.component.ts
|
||||
```
|
||||
|
||||
And in your HTML file:
|
||||
|
||||
```html reference
|
||||
https://github.com/zitadel/zitadel-angular/blob/main/src/app/components/user/user.component.html
|
||||
```
|
||||
|
||||
### Refresh token
|
||||
|
||||
If you want to add a refresh token to your application, navigate to the management console application and check the box in the configuration section.
|
||||
Then add `offline_access` to the scopes and add the following line:
|
||||
|
||||
```
|
||||
this.oauthService.setupAutomaticSilentRefresh();
|
||||
```
|
||||
|
||||
This line automatically refreshes a token before it expires.
|
||||
|
||||
## Completion
|
||||
|
||||
Congratulations! You have successfully integrated your Angular application with ZITADEL!
|
||||
|
||||
If you get stuck, consider checking out our [example](https://github.com/zitadel/zitadel-angular) application. This application includes all the functionalities mentioned in this quick-start. You can start by cloning the repository and replacing the _AuthConfig_ in the _AppModule_ with your own configuration. If you face issues, contact us or raise an issue on [GitHub](https://github.com/zitadel/zitadel).
|
||||
|
||||

|
||||
|
||||
### What's next?
|
||||
|
||||
Now that you have enabled authentication, it's time for you to add authorization to your application using ZITADEL APIs. To do this, you can refer to the [docs](/apis/introduction) or check out the ZITADEL Management Console code on [GitHub](https://github.com/zitadel/zitadel) which uses gRPC to access data.
|
||||
|
||||
For more information on how to create an Angular application, you can refer to [Angular](https://angular.io/start). If you want to learn more about the OAuth/OIDC library used above, consider reading the docs at [angular-oauth2-oidc](https://github.com/manfredsteyer/angular-oauth2-oidc).
|
||||
@@ -0,0 +1,179 @@
|
||||
---
|
||||
title: ZITADEL with Flutter
|
||||
sidebar_label: Flutter
|
||||
|
||||
---
|
||||
|
||||
This guide demonstrates how you integrate **ZITADEL** into a Flutter app. It refers to our example on [GitHub](https://github.com/zitadel/zitadel_flutter)
|
||||
|
||||
At the end of the guide you have a mobile application for **Android**, **iOS** and **Web** with the ability to authenticate users via ZITADEL.
|
||||
|
||||
If you need any other information about Flutter, head over to the [documentation](https://flutter.dev/).
|
||||
|
||||
## Setup Application
|
||||
|
||||
Before we can start building our application, we have to do a few configuration steps in ZITADEL Console.
|
||||
You will need to provide some information about your app. We recommend creating a new app to start from scratch. Navigate to your Project, then add a new application at the top of the page.
|
||||
Select **Native** application type and continue.
|
||||
|
||||

|
||||
|
||||
### Redirect URIs
|
||||
|
||||
With the Redirect URIs field, you tell ZITADEL where it is allowed to redirect users to after authentication.
|
||||
As our application will also support web, we have to make sure to set redirects for http and https, as well as a **custom-scheme** for our native Android and IOS Setup.
|
||||
|
||||
For our local web development, add a redirectURI for `http://localhost:4444/auth.html` with your custom port. For Android and IOS, add your **custom scheme**. In our case it is `com.example.zitadelflutter`.
|
||||
|
||||
<Callout type="warn" title="Use Custom Redirect URI!">
|
||||
|
||||
Your custom scheme has to be compliant with the OAuth 2.0
|
||||
authentication for mobile devices ([RFC 8252 specification](https://tools.ietf.org/html/rfc8252)).
|
||||
Otherwise your app might get rejected.
|
||||
|
||||
</Callout>
|
||||
|
||||
For development, you need to set dev mode to `true` to enable insecure HTTP and redirect to a `localhost` URI.
|
||||
|
||||
If you want to redirect the users back to a route on your application after they have logged out, add an optional redirect in the Post Logout URIs field.
|
||||
|
||||
Continue and create the application.
|
||||
|
||||
After creation, go to **token settings** and check the refresh token checkbox. This allows us to request a refresh_token via `offline_access` scope.
|
||||
Make sure to save the application.
|
||||
|
||||
### Client ID
|
||||
|
||||
After successful app creation, a pop-up will appear, showing the app's client ID. Copy the client ID, as you will need it to configure your Flutter application.
|
||||
|
||||
## Flutter Prerequisites
|
||||
|
||||
To move further in this quickstart, you'll need the following things prepared:
|
||||
|
||||
- Have Flutter (and Dart) installed ([how-to](https://flutter.dev/docs/get-started/install))
|
||||
- Have an IDE set up for developing Flutter ([how-to](https://flutter.dev/docs/get-started/editor))
|
||||
- Create a basic Flutter app ([how-to](https://flutter.dev/docs/get-started/codelab))
|
||||
- Create a "Native" application in ZITADEL
|
||||
|
||||
After you created the starter Flutter app, the app will show a simple, templated Flutter app.
|
||||
|
||||
### Install Dependencies
|
||||
|
||||
To authenticate users with ZITADEL in a mobile application, some specific packages are needed.
|
||||
The [RFC 8252 specification](https://tools.ietf.org/html/rfc8252) defines how
|
||||
[OAUTH2.0 for mobile and native apps](https://oauth.net/2/native-apps/) works.
|
||||
Basically, there are two major points in this specification:
|
||||
|
||||
1. It recommends to use [PKCE](https://oauth.net/2/pkce/)
|
||||
2. It does not allow third party apps to use an embedded web view for the login process,
|
||||
the app must open the login page within the default browser
|
||||
|
||||
First install [http](https://pub.dev/packages/http) a library for making HTTP calls,
|
||||
then [`flutter_web_auth_2`](https://pub.dev/packages/flutter_web_auth_2) and a secure storage to store the auth / refresh tokens [flutter_secure_storage](https://pub.dev/packages/flutter_secure_storage).
|
||||
|
||||
To install run:
|
||||
|
||||
```bash
|
||||
flutter pub add http
|
||||
flutter pub add oidc
|
||||
flutter pub add oidc_default_store
|
||||
```
|
||||
|
||||
#### Setup for Android
|
||||
|
||||
Navigate to your `AndroidManifest.xml` at `<projectRoot>/android/app/src/main/AndroidManifest.xml` and add the following activity with your custom scheme.
|
||||
|
||||
```xml reference
|
||||
https://github.com/zitadel/zitadel_flutter/blob/main/android/app/src/main/AndroidManifest.xml#L29-L38
|
||||
```
|
||||
|
||||
Furthermore, for `secure_storage`, you need to set the minimum SDK version to 18
|
||||
in `<projectRoot>/android/app/src/build.gradle`.
|
||||
|
||||
### Add Authentication
|
||||
|
||||
To reduce the commented default code, we will modify the `main.dart` file.
|
||||
|
||||
First, the `MyApp` class: it remains a stateless widget:
|
||||
|
||||
```dart reference
|
||||
https://github.com/zitadel/zitadel_flutter/blob/main/lib/main.dart#L14-L28
|
||||
```
|
||||
|
||||
Second, the `MyHomePage` class will remain a stateful widget with
|
||||
its title, we don't change any code here.
|
||||
|
||||
```dart reference
|
||||
https://github.com/zitadel/zitadel_flutter/blob/main/lib/main.dart#L30-L37
|
||||
```
|
||||
|
||||
What we'll change now, is the `_MyHomePageState` class to enable
|
||||
authentication via ZITADEL and remove the counter button of the starter application. We'll show the username of the authenticated user.
|
||||
|
||||
We define the needed elements for our state:
|
||||
|
||||
```dart
|
||||
var _busy = false;
|
||||
var _authenticated = false;
|
||||
var _username = '';
|
||||
final storage = const FlutterSecureStorage();
|
||||
```
|
||||
|
||||
Then the builder method, which does show the login button if you're not
|
||||
authenticated, a loading bar if the login process is going on and
|
||||
your name if you are authenticated:
|
||||
|
||||
```dart reference
|
||||
https://github.com/zitadel/zitadel_flutter/blob/main/lib/main.dart#L119-L159
|
||||
```
|
||||
|
||||
And finally the `_authenticate` method which calls the authorization endpoint,
|
||||
then fetches the user info and stores the tokens into the secure storage.
|
||||
|
||||
```dart reference
|
||||
https://github.com/zitadel/zitadel_flutter/blob/main/lib/main.dart#L45-L117
|
||||
```
|
||||
|
||||
Note that we have to use our http redirect URL for web applications or otherwise use our custom scheme for Android and iOS devices.
|
||||
To setup other platforms, read the documentation of the [Flutter Web Auth](https://pub.dev/packages/flutter_web_auth_2).
|
||||
|
||||
To ensure our application catches the callback URL, you have to create a `auth.html` file in the `/web`
|
||||
folder with the following content:
|
||||
|
||||
```html reference
|
||||
https://github.com/zitadel/zitadel_flutter/blob/main/web/auth.html
|
||||
```
|
||||
|
||||
Now, you can run your application for iOS and Android devices with
|
||||
|
||||
```bash
|
||||
flutter run
|
||||
```
|
||||
|
||||
or by directly selecting your device
|
||||
|
||||
```bash
|
||||
flutter run -d iphone
|
||||
```
|
||||
|
||||
For Web make sure you run the application on your fixed port such that it matches your redirect URI in your ZITADEL application. We used 4444 as port before so the command would look like this:
|
||||
|
||||
```bash
|
||||
flutter run -d chrome --web-port=4444
|
||||
```
|
||||
|
||||
Our Android and iOS Application opens ZITADEL's login within a custom tab, on Web a new tab is opened.
|
||||
|
||||
### Result
|
||||
|
||||
If everything works out correctly, your applications should look like this:
|
||||
|
||||
<div style={{display: 'grid', 'gridColumnGap': '1rem', 'gridTemplateColumns': '1fr 1fr', 'maxWidth': '500px', 'margin': '0 auto'}}>
|
||||
<img src="/docs/img/flutter/not-authed.png" alt="Unauthenticated" height="500px" />
|
||||
<img src="/docs/img/flutter/authed.png" alt="Flutter Authenticated" height="500px" />
|
||||
</div>
|
||||
|
||||
<div style={{display: 'grid', 'gridColumnGap': '1rem', 'gridTemplateColumns': '1fr 1fr', 'maxWidth': '800px', 'margin': '0 auto'}}>
|
||||
<img src="/docs/img/flutter/web-not-authed.png" alt="Unauthenticated" height="500px" />
|
||||
<img src="/docs/img/flutter/web-authed.png" alt="Flutter Authenticated" height="500px" />
|
||||
</div>
|
||||
@@ -0,0 +1,155 @@
|
||||
---
|
||||
title: ZITADEL with Go
|
||||
sidebar_label: Go
|
||||
---
|
||||
|
||||
This integration guide demonstrates the recommended way to incorporate ZITADEL into your Go web application.
|
||||
It explains how to enable user login in your application and how to fetch data from the user info endpoint.
|
||||
|
||||
> ℹ️ These examples and guides are based on our official [Go SDK](https://github.com/zitadel/zitadel-go).
|
||||
>
|
||||
> The SDK is a convenient wrapper around our low-level [OIDC library](https://github.com/zitadel/oidc). For most use cases, using the helpers provided in our [Go SDK](https://github.com/zitadel/zitadel-go) is the recommended approach for implementing authentication.
|
||||
|
||||
By the end of this guide, your application will have login functionality and will be able to access the current user's profile.
|
||||
|
||||
> This documentation references our [example](https://github.com/zitadel/zitadel-go) on GitHub.
|
||||
> You can either create your own application or directly run the example by providing the necessary arguments.
|
||||
|
||||
## Set up application
|
||||
|
||||
Before we begin developing our application, we need to perform a few configuration steps in the ZITADEL Console.
|
||||
You'll need to provide some information about your app. We recommend creating a new app to start from scratch. Navigate to your Project, then add a new application at the top of the page.
|
||||
Select the **Web** application type and continue.
|
||||
|
||||

|
||||
|
||||
We recommend that you use [Proof Key for Code Exchange (PKCE)](/apis/openidoauth/grant-types#proof-key-for-code-exchange) for all applications.
|
||||
|
||||

|
||||
|
||||
### Redirect URIs
|
||||
|
||||
The Redirect URIs field tells ZITADEL where it's allowed to redirect users after authentication. For development, you can set dev mode to `true` to enable insecure HTTP and redirect to a `localhost` URI.
|
||||
The Post-logout redirect send the users back to a route on your application after they have logged out.
|
||||
|
||||
> If you are following along with the [example](https://github.com/zitadel/zitadel-go), set the dev mode to `true`, the Redirect URIs to `http://localhost:8089/auth/callback` and Post-logout redirect URI to [http://localhost:8089/](http://localhost:8089/)>.
|
||||
|
||||

|
||||
|
||||
Continue and create the application.
|
||||
|
||||
### Client ID
|
||||
|
||||
After successful creation of the app, a pop-up will appear displaying the app's client ID. Copy the client ID, as you will need it to configure your Go client.
|
||||
|
||||

|
||||
|
||||
## Go setup
|
||||
|
||||
Now that you have configured your web application on the ZITADEL side, you can proceed with the integration of your Go client.
|
||||
|
||||
### Install ZITADEL Go SDK
|
||||
|
||||
To connect with ZITADEL, you need to install an OAuth/OIDC client. Run the following command:
|
||||
|
||||
```bash
|
||||
go get -u github.com/zitadel/zitadel-go/v3
|
||||
```
|
||||
|
||||
### Create the application server
|
||||
|
||||
Create a new go file with the content below. This will create an application with a home and profile page.
|
||||
|
||||
```go reference
|
||||
https://github.com/zitadel/zitadel-go/blob/next/example/app/app.go
|
||||
```
|
||||
|
||||
This will basically set up everything. So let's look at some parts of the code.
|
||||
|
||||
**Register authentication handler**:
|
||||
|
||||
For the authentication to work, the SDK needs some handlers in your application.
|
||||
In this example we will register them on the `/auth/` prefix.
|
||||
The SDK itself will then register three routes on that to be able to:
|
||||
- start the authentication process and redirect to the Login UI (`/auth/login`)
|
||||
- continue with the authentication process after the login UI (`/auth/callback`)
|
||||
- terminate the session (`/auth/logout`)
|
||||
|
||||
```go
|
||||
router.Handle("/auth/", z.Authentication)
|
||||
```
|
||||
|
||||
***Authentication checks***
|
||||
|
||||
To ensure the user is authenticated before they are able to use your application, the middleware provides two options:
|
||||
- You can either require the user to be authenticated. If they haven't already, they will be automatically redirected to the Login UI:
|
||||
```go
|
||||
mw.RequireAuthentication()(handler)
|
||||
```
|
||||
- You can just check the user's authentication status, but still continue serving the page:
|
||||
```go
|
||||
mw.CheckAuthentication()(handler)
|
||||
```
|
||||
|
||||
***Authentication context***
|
||||
|
||||
If you used either of the authentication checks above, you can then access context information in your handler:
|
||||
```go
|
||||
mw.Context(req.Context())
|
||||
```
|
||||
|
||||
### Add pages to your application
|
||||
|
||||
To be able to serve these pages create a `templates` directory in the same folder as you just created the go file.
|
||||
Now create two HTML files in the new `templates` folder and copy the content of the examples:
|
||||
|
||||
**home.html**
|
||||
|
||||
The home page will display a short welcome message and allow the user to manually start the login process.
|
||||
|
||||
```go reference
|
||||
https://github.com/zitadel/zitadel-go/blob/next/example/app/templates/home.html
|
||||
```
|
||||
|
||||
**profile.html**
|
||||
|
||||
The profile page will display the Userinfo from the authentication context and allow the user to logout.
|
||||
|
||||
```go reference
|
||||
https://github.com/zitadel/zitadel-go/blob/next/example/app/templates/profile.html
|
||||
```
|
||||
|
||||
### Start your application
|
||||
|
||||
You will need to provide some values for the program to run:
|
||||
- `domain`: Your ZITADEL Custom Domain, e.g. my-domain.zitadel.cloud
|
||||
- `key`: Random secret string. Used for symmetric encryption of state parameters, cookies and PKCE.
|
||||
- `clientID`: The clientID provided by ZITADEL
|
||||
- `redirectURI`: The redirectURI registered at ZITADEL
|
||||
- `port`: The port on which the API will be accessible, default it 8089
|
||||
|
||||
```bash
|
||||
go run main.go --domain <custom domain> --key <key> -- clientID <clientID> --redirectURI <redirectURI>
|
||||
```
|
||||
|
||||
This could look like:
|
||||
|
||||
```bash
|
||||
go run main.go --domain my-domain.zitadel.cloud --key XKv2Lqd7YAq13NUZVUWZEWZeruqyzViM --clientID 243861220627644836@example --redirectURI http://localhost:8089/auth/callback
|
||||
```
|
||||
|
||||
If you then visit on http://localhost:8089 you should get the following screen:
|
||||
|
||||

|
||||
|
||||
By clicking on `Login` you will be redirected to your ZITADEL instance. After login with your existing user you will be presented the profile page:
|
||||
|
||||

|
||||
|
||||
## Completion
|
||||
|
||||
Congratulations! You have successfully integrated your Go application with ZITADEL!
|
||||
|
||||
If you get stuck, consider checking out our [example](https://github.com/zitadel/zitadel-go) application.
|
||||
This application includes all the functionalities mentioned in this quickstart.
|
||||
You can directly start it with your own configuration. If you face issues, contact us or raise an issue on [GitHub](https://github.com/zitadel/zitadel-go/issues).
|
||||
@@ -0,0 +1,176 @@
|
||||
---
|
||||
title: ZITADEL with Java Spring Boot
|
||||
sidebar_label: Java Spring Boot
|
||||
---
|
||||
|
||||
This integration guide demonstrates the recommended way to incorporate ZITADEL into your Spring Boot web application.
|
||||
It explains how to enable user login in your application and how to fetch data from the user info endpoint.
|
||||
|
||||
By the end of this guide, your application will have login functionality and will be able to access the current user's profile.
|
||||
|
||||
<Callout>
|
||||
This documentation references our [example](https://github.com/zitadel/zitadel-java) on GitHub.
|
||||
You can either create your own application or directly run the example by providing the necessary arguments.
|
||||
</Callout>
|
||||
|
||||
## Set up application
|
||||
|
||||
Before we begin developing our application, we need to perform a few configuration steps in the ZITADEL Console.
|
||||
You'll need to provide some information about your app. We recommend creating a new app to start from scratch. Navigate to your Project, then add a new application at the top of the page.
|
||||
Select the **Web** application type and continue.
|
||||
|
||||

|
||||
|
||||
We recommend that you use [Proof Key for Code Exchange (PKCE)](/apis/openidoauth/grant-types#proof-key-for-code-exchange) for all applications.
|
||||
|
||||

|
||||
|
||||
### Redirect URIs
|
||||
|
||||
The Redirect URIs field tells ZITADEL where it's allowed to redirect users after authentication. For development, you can set dev mode to `true` to enable insecure HTTP and redirect to a `localhost` URI.
|
||||
The Post-logout redirect send the users back to a route on your application after they have logged out.
|
||||
|
||||
<Callout>
|
||||
If you are following along with the [example](https://github.com/zitadel/zitadel-java), set the dev mode to `true`, the Redirect URIs to `http://localhost:18080/webapp/login/oauth2/code/zitadel` and Post redirect URI to `http://localhost:18080/webapp`.
|
||||
</Callout>
|
||||
|
||||

|
||||
|
||||
Continue and create the application.
|
||||
|
||||
### Client ID
|
||||
|
||||
After successful creation of the app, a pop-up will appear displaying the app's client ID. Copy the client ID, as you will need it to configure your Java client.
|
||||
|
||||

|
||||
|
||||
## Spring setup
|
||||
|
||||
Now that you have configured your web application on the ZITADEL side, you can proceed with the integration of your Spring client.
|
||||
This guide will reference the [example repository](https://github.com/zitadel/zitadel-java) and explain the necessary steps taken in there.
|
||||
If your starting from scratch, you can use the Spring Initializer with the [following setup](https://start.spring.io/#!type=maven-project&language=java&platformVersion=3.2.1&packaging=jar&jvmVersion=17&dependencies=web,thymeleaf,security,oauth2-client,lombok) as a base.
|
||||
|
||||
### Support classes
|
||||
|
||||
To be able to take the most out of ZITADELs RBAC, we first need to create a GrantedAuthoritiesMapper, that will map the role claims (`urn:zitadel:iam:org:project:roles`)
|
||||
into Spring Security `authiorities`, which can be used later on to determine the granted permissions.
|
||||
|
||||
So in your application, create a 'support/zitadel' package and in there the `ZitadelGrantedAuthoritiesMapper.java`:
|
||||
|
||||
```java reference
|
||||
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/java/demo/support/zitadel/ZitadelGrantedAuthoritiesMapper.java
|
||||
```
|
||||
|
||||
The following two classes will provide you the possibility to access and use the user's token for requests to another API, e.g. the Spring Boot API example.
|
||||
|
||||
Directly create them in the `support` package.
|
||||
|
||||
```java reference
|
||||
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/java/demo/support/TokenAccessor.java
|
||||
```
|
||||
|
||||
```java reference
|
||||
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/java/demo/support/AccessTokenInterceptor.java
|
||||
```
|
||||
|
||||
### Application server configuration
|
||||
|
||||
As we have now our support classes, we can now create and configure the application server (and API client) itself.
|
||||
|
||||
In a new `config` package, create first the `WebClientConfig.java`, which will provide a RestTemplate using the previously created AccessTokenInterceptor:
|
||||
|
||||
```java reference
|
||||
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/java/demo/config/WebClientConfig.java
|
||||
```
|
||||
|
||||
Additionally also create the `WebSecurityConfig.java` in the same package. This class will take care of the authentication, redirecting the user to the login,
|
||||
mapping the claims (using the ZitadelGrantedAuthoritiesMapper) and also provide the possibility for logout:
|
||||
|
||||
```java reference
|
||||
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/java/demo/config/WebSecurityConfig.java
|
||||
```
|
||||
|
||||
For the authentication (and the server in general) to work, the application needs some configuration, so please provide the following to your `application.yml` (resources folder):
|
||||
|
||||
```yaml reference
|
||||
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/resources/application.yml
|
||||
```
|
||||
|
||||
Note that both the `issuer-uri` as well as the `client-id` are only placeholders. You can either change them in here using the values provided by ZITADEL
|
||||
or pass them later on as arguments when starting the application.
|
||||
|
||||
### Add pages to your application
|
||||
|
||||
To be able to serve these pages create a `templates` directory in the `resources` folder.
|
||||
Now create three HTML files in the new `templates` folder and copy the content of the examples:
|
||||
|
||||
**index.html**
|
||||
|
||||
The home page will display the Userinfo from the authentication context and the granted roles / Spring security authorities.
|
||||
|
||||
```html reference
|
||||
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/resources/templates/index.html
|
||||
```
|
||||
|
||||
**fragments.html**
|
||||
|
||||
The navigation to switch between the home and tasks page and allows the user to logout.
|
||||
|
||||
```html reference
|
||||
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/resources/templates/fragments.html
|
||||
```
|
||||
|
||||
**tasks.html**
|
||||
|
||||
The tasks page allows to interact with the Spring Boot API example and display / add new tasks.
|
||||
|
||||
```html reference
|
||||
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/resources/templates/tasks.html
|
||||
```
|
||||
|
||||
**UiController**
|
||||
|
||||
To serve these pages and handler their actions, you finally need a `UiController.java`:
|
||||
|
||||
```java reference
|
||||
https://github.com/zitadel/zitadel-java/blob/main/web/src/main/java/demo/web/UiController.java
|
||||
```
|
||||
|
||||
### Start your application
|
||||
|
||||
In case you've created your own application and depending on your development setup you might need to build the application first:
|
||||
|
||||
```bash
|
||||
mvn clean package -DskipTests
|
||||
```
|
||||
|
||||
You will need to provide the `issuer-uri` (your Custom Domain) and the `client-id` previously created:
|
||||
|
||||
```bash
|
||||
java \
|
||||
-Dspring.security.oauth2.client.provider.zitadel.issuer-uri=<see configuration above> \
|
||||
-Dspring.security.oauth2.client.registration.zitadel.client-id=<see configuration above> \
|
||||
-jar web/target/web-0.0.2-SNAPSHOT.jar
|
||||
```
|
||||
|
||||
This could look like:
|
||||
|
||||
```bash
|
||||
java \
|
||||
-Dspring.security.oauth2.client.provider.zitadel.issuer-uri=https://my-domain.zitadel.cloud \
|
||||
-Dspring.security.oauth2.client.registration.zitadel.client-id=243861220627644836@example \
|
||||
-jar web/target/web-0.0.2-SNAPSHOT.jar
|
||||
```
|
||||
|
||||
If you then visit on [http://localhost:18080/webapp](http://localhost:18080/webapp) you should directly be redirected to your ZITADEL instance.
|
||||
After login with your existing user you will be presented the profile page:
|
||||
|
||||

|
||||
|
||||
## Completion
|
||||
|
||||
Congratulations! You have successfully integrated your Spring Boot web application with ZITADEL!
|
||||
|
||||
If you get stuck, consider checking out our [example](https://github.com/zitadel/zitadel-java) application.
|
||||
This application includes all the functionalities mentioned in this quickstart.
|
||||
You can directly start it with your own configuration. If you face issues, contact us or raise an issue on [GitHub](https://github.com/zitadel/zitadel-java/issues).
|
||||
@@ -0,0 +1,179 @@
|
||||
---
|
||||
title: ZITADEL with Next.js - A B2B Scenario
|
||||
sidebar_label: Next.js - B2B
|
||||
---
|
||||
|
||||
This is our ZITADEL [Next.js](https://nextjs.org/) B2B template. It shows how to authenticate as a user with multiple organizations. The application shows your users roles on the selected organizations, other projects your organization is allowed to use and other users having a grant to use the application.
|
||||
|
||||
If you need more info on B2B use cases consider reading our guide for the [B2B solution scenario](/guides/solution-scenarios/b2b).
|
||||
|
||||
> You can follow along with the template code in our [zitadel-nextjs-b2b](https://github.com/zitadel/zitadel-nextjs-b2b) repo.
|
||||
|
||||

|
||||
|
||||
## What does it do?
|
||||
|
||||
Users with `view` role can view granted projects on their organization which were granted by your organization (owning this portal application).
|
||||
Users with `admin` role can view granted projects and list users of the selected organization who are granted to use the portal application too.
|
||||
|
||||
## Setup Vendor application and users in ZITADEL
|
||||
|
||||
First we need to create an organization that holds the Vendor's users, projects and applications.
|
||||
|
||||
### Vendor Organization
|
||||
|
||||
Navigate to `https://$CUSTOM_DOMAIN.zitadel.cloud/ui/console/orgs` (replace $CUSTOM_DOMAIN), and click on the button "New".
|
||||
Toggle the setting "Use your personal account as organization owner".
|
||||
|
||||
Enter the name `Demo-Vendor`, and click "Create". Then click on that organization.
|
||||
|
||||
### Portal Web Application
|
||||
|
||||
To setup this sample you have to create a project and an application in the vendor organization (`Demo-Vendor`) first.
|
||||
|
||||
Open the Management Console (`https://$CUSTOM_DOMAIN.zitadel.cloud/ui/console/projects`) and create a new project. Let's call it `Portal`.
|
||||
|
||||
Then on the project detail page click on new application and enter a name for this app.
|
||||
Let's call this one `portal-web`.
|
||||
Select `Web`, continue, `CODE`, then enter `http://localhost:3000/api/auth/callback/zitadel` for the redirect, and `http://localhost:3000` for the post redirect. Then press on `create`.
|
||||
Because the requests from your NextJS application to ZITADEL are made on the server side, you can safely select `CODE`. You will get a secret at the end of the stepper. With NextAuth your secret never gets exposed on the browser since it is kept in your NextJS server.
|
||||
|
||||
Copy the "Resource Id" of the project `Portal` as you will need this in your environment configuration file later.
|
||||
|
||||
Click on the application `portal-web`.
|
||||
On the application detail page click on the section under redirect settings and enable `Development Mode`. This will allow you application to work on `localhost:3000`.
|
||||
To read the user data and roles from ID Token, go to the section Token Settings and make sure both checkboxes, `User roles inside ID Token` and `User Info inside ID Token` are enabled.
|
||||
Make sure to save your changes.
|
||||
|
||||
Copy the "Resource Id" of the application `portal-web` as you will need this in your environment configuration file later.
|
||||
|
||||
### Roles
|
||||
|
||||
To setup the needed roles for your project, navigate to your `Portal` project, and add the following roles
|
||||
|
||||
| Key | Display Name | Group | Description |
|
||||
| :----- | :------------ | :---- | ---------------------------------------------------------------------- |
|
||||
| admin | Administrator | | The administrator, allowed to read granted projects and to user grants |
|
||||
| reader | Reader | | A user who is allowed to read his organizations granted projects only |
|
||||
|
||||
Now in the `General` section of the Portal project, make sure to enable `Assert Roles on Authentication`.
|
||||
This makes sure that roles, which is used by the application to enable UI components, are set in your OIDC ID Token.
|
||||
|
||||
### Service User
|
||||
|
||||
To make the application work you need a service user which loads granted-projects and user-grants for you.
|
||||
In the B2B-Demo organization, navigate to `Users` in navigation of Management Console, click on `Service Users` and create a new user.
|
||||
Let's set its username to `nextjs` and its name to `NextJS`. Then press `create`.
|
||||
|
||||
On the detail page of that user, navigate to "Personal Access Tokens" and add a new entry, set an optional expiration date.
|
||||
|
||||
Copy the generated Token as you will need this in your environment configuration file later.
|
||||
|
||||
Go back to the `Portal` project and add the Service User as Manager (top right).
|
||||
Make sure to select `Project Owner Viewer` as the management role.
|
||||
|
||||
To show granted projects, go to the `Demo-Vendor` organization and add the Service User as `Org Project Permission Editor` Manager.
|
||||
|
||||
## Configuration
|
||||
|
||||
Now clone this project and navigate to its root folder.
|
||||
Create a file `.env.local` and copy paste the following:
|
||||
|
||||
```text
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
NEXT_PUBLIC_ZITADEL_ISSUER=https://$CUSTOM_DOMAIN.zitadel.cloud
|
||||
ZITADEL_API=https://$CUSTOM_DOMAIN.zitadel.cloud
|
||||
ORG_ID=${YOUR_ORG_ID}
|
||||
PROJECT_ID=${PROJECT_ID}
|
||||
ZITADEL_CLIENT_ID=${CLIENT_ID}
|
||||
SERVICE_ACCOUNT_ACCESS_TOKEN=${SERVICE_ACCOUNT_SECRET}
|
||||
NEXTAUTH_SECRET=randomsecret
|
||||
```
|
||||
|
||||
Replace the values as follows
|
||||
|
||||
`NEXTAUTH_URL`: Base url of this demo app (B2B portal); runs per default on [http://localhost:3000](http://localhost:3000)
|
||||
|
||||
`NEXT_PUBLIC_ZITADEL_ISSUER`: The url to your zitadel instance. When using zitadel.cloud for this demo you can find the domain of your ZITADEL instance in the customer portal. You can also find this information by going to your application `portal-web` and click 'URLs' in the navigation. The variable is prefixed with `NEXT_PUBLIC_` such that it can be accessed from the client.
|
||||
|
||||
`ZITADEL_API`: URL of the Management API. Typically the same as `ZITADEL_ISSUER`.
|
||||
|
||||
`ORG_ID`: We will create an organization during later steps. You can find `${YOUR_ORG_ID}` by selecting the `Demo-Vendor` organization in Console. `${YOUR_ORG_ID}` is displayed on top of the organization detail page as "Resource Id".
|
||||
|
||||
`PROJECT_ID`: You can find `${PROJECT_ID}` by clicking on "Projects" in the navigation and select the Project `Portal`. `${PROJECT_ID}` is displayed on the top as "Resource Id".
|
||||
|
||||
`ZITADEL_CLIENT_ID`: Having the project `Portal` selected, click on the Application `portal-web`. `${CLIENT_ID}` is displayed as a field in the OIDC configuration, labelled "Client ID" and has the format `12345678@portal`.
|
||||
|
||||
`SERVICE_ACCOUNT_ACCESS_TOKEN`: Set up a service user, add a Personal Access Token and copy the secret here (see below).
|
||||
|
||||
## Install and Run
|
||||
|
||||
To run this sample locally you need to install dependencies first.
|
||||
|
||||
Type and execute:
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
then, to run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
```
|
||||
|
||||
and open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
## Create a customer organization
|
||||
|
||||
### Customer organization
|
||||
|
||||
Create a new organization in Console. Easiest way is to use the organization dropdown on the top left.
|
||||
Let's call this new organization `Demo-Customer`.
|
||||
|
||||
### Users
|
||||
|
||||
Now switch back to the organization `Demo-Customer` and [create a new user](/guides/manage/console/users-overview#create-user) in this organization.
|
||||
Let's call the first user `Alice Admin`. Create a second user called `Eric Employee`.
|
||||
|
||||
### Administrator Role
|
||||
|
||||
We want to enable Alice to assign roles to users in her organization in a self-service manner.
|
||||
To make this happen, we need to assign Alice an [Administrator Role](/concepts/structure/managers) within the Organization `Demo-Customer`.
|
||||
|
||||
Still in the organization `Demo-Customer`, navigate to Organization. Click on the plus on the top right and give `Alice Admin` the Administrator Role `Org Owner`.
|
||||
|
||||
Login with your user on the customer organization to validate the setup.
|
||||
|
||||
## Create a project grant
|
||||
|
||||
### Organization Grant
|
||||
|
||||
Switch to the `Demo-Vendor` organization, select Projects in the navigation, and click on `Portal` and then `Grants`.
|
||||
[Grant all roles of the Project](/guides/manage/console/projects-overview#granted-projects-b2b) to the organization `demo-customer.$CUSTOM_DOMAIN.zitadel.cloud`.
|
||||
|
||||
### Authorization
|
||||
|
||||
As you have guessed, these two users need to be authorized.
|
||||
On the `Demo-Customer` organization, navigate to Projects and select "Granted Projects" in the sub-navigation.
|
||||
Select the project portal `Portal` and navigate to "Authorizations".
|
||||
|
||||
Give `Alice Admin` the roles `reader` and `admin`.
|
||||
`Eric Employee` will get only the role `reader`.
|
||||
|
||||
### Login
|
||||
|
||||
You should be able to login to the Demo Application with `Alice Admin` and see all granted projects.
|
||||
|
||||
You can log out and log in with `Eric Employee` and you should only have access to the granted projects, but not to the Authorizations tab.
|
||||
|
||||
## What next
|
||||
|
||||
You could create another project (eg, `Data Cube`) and grant that project to the customer organization. The granted project should appear after a reload automatically. This gives you an idea of how you could do Service Discovery with ZITADEL.
|
||||
|
||||
You could also build out the code (PRs welcome :wink:) for this application, for example:
|
||||
|
||||
- Create a mock `datacube-web` application and show how SSO between the portal and the application works with ZITADEL.
|
||||
- Implement a feature in the Authorization tab to assign roles directly from the customer portal.
|
||||
@@ -0,0 +1,195 @@
|
||||
---
|
||||
title: ZITADEL with Next.js
|
||||
sidebar_label: Next.js
|
||||
---
|
||||
|
||||
This is our Zitadel [Next.js](https://nextjs.org/) template. It shows how to authenticate as a user and retrieve user information from the OIDC endpoint.
|
||||
|
||||
> The template code is part of our zitadel-nextjs repo. Take a look [here](https://github.com/zitadel/zitadel-nextjs).
|
||||
|
||||
## Getting Started
|
||||
|
||||
### Install dependencies
|
||||
|
||||
To install the dependencies type:
|
||||
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
then to run the app:
|
||||
|
||||
```bash
|
||||
yarn dev
|
||||
```
|
||||
|
||||
then open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
## Setup Application and Get Keys
|
||||
|
||||
Before we can start building our application, we have to do a few configuration steps in ZITADEL Console.
|
||||
You will need to provide some information about your app.
|
||||
|
||||
Navigate to your Project, then add a new application at the top of the page.
|
||||
Select Web application type and continue.
|
||||
We use [Authorization Code](/apis/openidoauth/grant-types#authorization-code)for our NextJS application.
|
||||
Select `CODE` in the next step. This makes sure you still get a secret. Note that the secret never gets exposed on the browser and is therefore kept in a confidential environment.
|
||||
|
||||

|
||||
### Redirect URIs
|
||||
|
||||
With the Redirect URIs field, you tell ZITADEL where it is allowed to redirect users to after authentication. For development, you can set dev mode to `true` to enable insecure HTTP and redirect to a `localhost` URI.
|
||||
|
||||
> If you are following along with the [example](https://github.com/zitadel/zitadel-nextjs), set dev mode to `true` and the Redirect URIs to `http://localhost:3000/api/auth/callback/zitadel`.
|
||||
|
||||
If you want to redirect the users back to a route on your application after they have logged out, add an optional redirect in the Post Logout URIs field.
|
||||
|
||||
Continue and create the application.
|
||||
|
||||
### Client ID
|
||||
|
||||
After successful app creation, a pop-up will appear, showing the app's client ID. Copy the client ID, as you will need it to configure your NextJS app.
|
||||
|
||||
## NextJS Setup
|
||||
|
||||
Now that you have your web application configured on the ZITADEL side, you can go ahead and integrate your NextJS app.
|
||||
|
||||
### Configuration
|
||||
|
||||
NextAuth.js exposes a REST API which is used by your client.
|
||||
To setup your configuration, create a file called `src/lib/auth.ts`.
|
||||
You can directly import the ZITADEL provider from [next-auth](https://next-auth.js.org/providers/zitadel).
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/example-auth-nextjs/blob/main/src/lib/auth.ts
|
||||
```
|
||||
|
||||
You can overwrite the profile callback, just append it to the ZITADEL provider.
|
||||
|
||||
```ts
|
||||
// ...
|
||||
ZitadelProvider({
|
||||
issuer: process.env.ZITADEL_ISSUER,
|
||||
clientId: process.env.ZITADEL_CLIENT_ID,
|
||||
clientSecret: process.env.ZITADEL_CLIENT_SECRET,
|
||||
async profile(profile) {
|
||||
return {
|
||||
id: profile.sub,
|
||||
name: profile.name,
|
||||
firstName: profile.given_name,
|
||||
lastName: profile.family_name,
|
||||
email: profile.email,
|
||||
loginName: profile.preferred_username,
|
||||
image: profile.picture,
|
||||
};
|
||||
},
|
||||
}),
|
||||
// ...
|
||||
```
|
||||
|
||||
If you want to request a refresh token, you can overwrite the JWT callback and add the `offline_access` scope.
|
||||
|
||||
```ts
|
||||
// ...
|
||||
async function refreshAccessToken(token: JWT): Promise<JWT> {
|
||||
try {
|
||||
const issuer = await Issuer.discover(process.env.ZITADEL_ISSUER ?? '');
|
||||
const client = new issuer.Client({
|
||||
client_id: process.env.ZITADEL_CLIENT_ID || '',
|
||||
token_endpoint_auth_method: 'none',
|
||||
});
|
||||
|
||||
const { refresh_token, access_token, expires_at } = await client.refresh(token.refreshToken as string);
|
||||
|
||||
return {
|
||||
...token,
|
||||
accessToken: access_token,
|
||||
expiresAt: (expires_at ?? 0) * 1000,
|
||||
refreshToken: refresh_token, // Fall back to old refresh token
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error during refreshAccessToken', error);
|
||||
|
||||
return {
|
||||
...token,
|
||||
error: 'RefreshAccessTokenError',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// ...
|
||||
ZitadelProvider({
|
||||
issuer: process.env.ZITADEL_ISSUER,
|
||||
clientId: process.env.ZITADEL_CLIENT_ID,
|
||||
clientSecret: process.env.ZITADEL_CLIENT_SECRET,
|
||||
async profile(profile) {
|
||||
return {
|
||||
id: profile.sub,
|
||||
name: profile.name,
|
||||
firstName: profile.given_name,
|
||||
lastName: profile.family_name,
|
||||
email: profile.email,
|
||||
loginName: profile.preferred_username,
|
||||
image: profile.picture,
|
||||
};
|
||||
},
|
||||
}),
|
||||
// ...
|
||||
```
|
||||
|
||||
To be able to connect to ZITADEL, make sure to add `http://localhost:3000/api/auth/callback/zitadel` as redirect url to your app.
|
||||
For simplicity reasons we set the default to the one that next-auth provides us. You'll be able to change the redirect later if you want to.
|
||||
|
||||
Hit Create, then in the detail view of your application make sure to enable dev mode. Dev mode ensures that you can start an auth flow from a non https endpoint for testing.
|
||||
|
||||
Now go to Token settings and check the checkbox for **User Info inside ID Token** to get your users name directly on authentication.
|
||||
|
||||
### Environment
|
||||
|
||||
Create a file `.env` in the root of the project and add the following keys to it.
|
||||
You can find your Issuer Url on the application detail page in console.
|
||||
|
||||
```env reference
|
||||
https://github.com/zitadel/zitadel-nextjs/blob/main/.env.example
|
||||
```
|
||||
|
||||
next-auth requires a secret for all providers, so just define a random value here.
|
||||
|
||||
### User interface
|
||||
|
||||
Now we can start editing the homepage by modifying `src/app/profile/page.tsx`. On the homepage, your authenticated user or a Signin button is shown.
|
||||
|
||||
Add the following component to render the UI elements:
|
||||
|
||||
```ts reference
|
||||
|
||||
https://github.com/zitadel/example-auth-nextjs/blob/main/src/app/profile/page.tsx
|
||||
```
|
||||
|
||||
Note that the signIn method requires the id of our provider which is in our case `zitadel`.
|
||||
|
||||
### Userinfo API
|
||||
|
||||
To show user information, you can either use the idToken data, or call the userinfo endpoint.
|
||||
In this example, we call the userinfo endpoint to load user data.
|
||||
To implement the API, you can create a file under the `src/app/api/userinfo/` folder and call it `route.ts`.
|
||||
The file should look like the following.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-nextjs/blob/main/src/app/api/userinfo/route.ts
|
||||
```
|
||||
|
||||
### Session state
|
||||
|
||||
To allow session state to be shared between pages - which improves performance, reduces network traffic and avoids component state changes while rendering - you can use the NextAuth.js Provider in `src/app/providers.tsx`.
|
||||
Take a look at the template `providers.tsx`.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-nextjs/blob/main/src/app/providers.tsx
|
||||
```
|
||||
|
||||
Last thing: create a `page.tsx` in `src/app/profile/` which renders the callback page.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-nextjs/blob/main/src/app/profile/page.tsx
|
||||
```
|
||||
@@ -0,0 +1,241 @@
|
||||
---
|
||||
title: ZITADEL with Django Python
|
||||
sidebar_label: Django
|
||||
---
|
||||
|
||||
import SetupPython from '../imports/_setup_python.mdx';
|
||||
import SetupDjango from '../imports/_setup_django.mdx';
|
||||
import SetupDotenv from '../imports/_setup_dotenv.mdx';
|
||||
|
||||
This integration guide demonstrates the recommended way to incorporate ZITADEL into your Django Python application.
|
||||
It explains how to enable user login in your application and how to incorporate the ZITADEL users into the existing AuthenticationBackend.
|
||||
|
||||
By the end of this guide, your application will have login functionality with basic role mapping, admin console and polls as described in the Django guide.
|
||||
|
||||
<Callout>
|
||||
This documentation references our [example](https://github.com/zitadel/example-django-python-oidc) on GitHub.
|
||||
</Callout>
|
||||
|
||||
## ZITADEL setup
|
||||
|
||||
Before we can start building our application, we have to do a few configuration steps in ZITADEL Management Console.
|
||||
|
||||
### Project roles
|
||||
|
||||
The Example expects [user roles](/guides/integrate/retrieve-user-roles) to be returned after login.
|
||||
This example expects 3 different roles:
|
||||
- `admin`: superuser with permissions to use the admin console
|
||||
- `staff`: user with permissions to see results of the polls
|
||||
- `user`: normal user with permission to vote on the existing polls
|
||||
|
||||
In your project settings make sure the "Assert Roles On Authentication" is enabled.
|
||||
|
||||

|
||||
|
||||
In the project Role tab, add 3 special roles:
|
||||
|
||||
- `admin`
|
||||
- `staff`
|
||||
- `user`
|
||||
|
||||
If none of the roles is provided as a user, the user in Django will not be created.
|
||||
|
||||

|
||||
|
||||
Finally, we can assign the roles to users in the project's authorizations tab.
|
||||
|
||||

|
||||
|
||||
### Set up application and obtain secrets
|
||||
|
||||
Next you will need to provide some information about your app.
|
||||
|
||||
In your Project, add a new application at the top of the page.
|
||||
Select Web application type and continue.
|
||||
We use [Authorization Code](/apis/openidoauth/grant-types#authorization-code) for our Django application.
|
||||
|
||||

|
||||
|
||||
Select `CODE` in the next step. This makes sure you still get a secret. Note that the secret never gets exposed on the browser and is therefore kept in a confidential environment. Safe the generated secret for later use.
|
||||
|
||||

|
||||
|
||||
With the Redirect URIs field, you tell ZITADEL where it is allowed to redirect users to after authentication. For development, you can set dev mode to `true` to enable insecure HTTP and redirect to a `localhost` URI.
|
||||
|
||||
For the example application we are writing use:
|
||||
|
||||
- `http://localhost:8000/oidc/callback/` as Redirect URI
|
||||
- `http://localhost:8000/oidc/logout/` as post-logout URI.
|
||||
|
||||

|
||||
|
||||
After the final step you are presented with a client ID and secret.
|
||||
Copy and paste them to a safe location for later use by the application.
|
||||
The secret will not be displayed again, but you can regenerate one if you loose it.
|
||||
|
||||
## Setup new Django application
|
||||
|
||||
### Setup Python
|
||||
|
||||
<SetupPython components={props.components} />
|
||||
|
||||
### Install dependencies
|
||||
|
||||
For this example we need the following dependencies:
|
||||
- `django`: to create an API with django
|
||||
- `python-dotenv`: to use environment variables in the configuration
|
||||
- `mozilla-django-oidc`: client-side OIDC functionality
|
||||
|
||||
For the dependencies we need a requirements.txt-file with the following content:
|
||||
|
||||
```python reference
|
||||
https://github.com/zitadel/example-python-django-oidc/blob/main/requirements.txt
|
||||
```
|
||||
|
||||
Then install all dependencies with:
|
||||
```bash
|
||||
python -m pip install -U requirements.txt
|
||||
```
|
||||
|
||||
The used base is the "Writing your first Django app" from the Django documentation under [https://docs.djangoproject.com/en/5.0/intro/](https://docs.djangoproject.com/en/5.0/intro/),
|
||||
which has documented additional parts in to use [mozilla-django-oidc](https://github.com/mozilla/mozilla-django-oidc) to integrate ZITADEL as AuthenticationBackend.
|
||||
|
||||
<Callout>
|
||||
Skip this step if you are connecting ZITADEL to an existing application.
|
||||
</Callout>
|
||||
|
||||
## Define the Django app
|
||||
|
||||
### Create the settings.py to include mozilla-django-oidc
|
||||
|
||||
To use the mozilla-django-oidc as AuthenticationBackend, there are several things to add to the settings.py, as described in the [documentation "Add settings to settings.py"](https://mozilla-django-oidc.readthedocs.io/en/stable/installation.html#add-settings-to-settings-py):
|
||||
|
||||
Add INSTALLED_APPS:
|
||||
|
||||
```python
|
||||
INSTALLED_APPS = [
|
||||
...
|
||||
"mozilla_django_oidc", # Load after auth
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
Add MIDDLEWARE:
|
||||
|
||||
```python
|
||||
MIDDLEWARE = [
|
||||
#...
|
||||
"mozilla_django_oidc.middleware.SessionRefresh",
|
||||
]
|
||||
```
|
||||
|
||||
Add AUTHENTICATION_BACKENDS:
|
||||
|
||||
```python
|
||||
AUTHENTICATION_BACKENDS = (
|
||||
"mysite.backend.PermissionBackend",
|
||||
)
|
||||
```
|
||||
|
||||
Add configuration:
|
||||
|
||||
```python reference
|
||||
https://github.com/zitadel/example-python-django-oidc/blob/main/mysite/settings.py#L130-L174
|
||||
```
|
||||
|
||||
and create a ".env"-file in the root folder with the configuration:
|
||||
|
||||
```bash
|
||||
ZITADEL_PROJECT = "ID of the project you created the application in ZITADEL"
|
||||
OIDC_RP_CLIENT_ID = "ClientID provided by the created application in ZITADEL"
|
||||
OIDC_RP_CLIENT_SECRET = "ClientSecret provided by the created application in ZITADEL"
|
||||
OIDC_OP_BASE_URL = "Base URL to the ZITADEL instance"
|
||||
```
|
||||
|
||||
which should then look something like this:
|
||||
|
||||
```bash
|
||||
ZITADEL_PROJECT = "249703732336418457"
|
||||
OIDC_RP_CLIENT_ID = "249703852243222581@python"
|
||||
OIDC_RP_CLIENT_SECRET = "Zy3OOHaMBTj2sfamW77Vak5BeQ3nEpOf7suPKTnJKaScMh0lPJqUeDOZmgL3bds0"
|
||||
OIDC_OP_BASE_URL = "https://example.zitadel.cloud"
|
||||
```
|
||||
|
||||
### AuthenticationBackend definition
|
||||
|
||||
To create and update the users regarding the roles given in the authentications in ZITADEL a Subclass of OIDCAuthenticationBackend has to be created:
|
||||
|
||||
```python reference
|
||||
https://github.com/zitadel/example-python-django-oidc/blob/main/mysite/backend.py
|
||||
```
|
||||
|
||||
Which handles the users differently depending on if there are roles associated to:
|
||||
- `admin` -> superuser
|
||||
- `staff` -> staff
|
||||
- `user` -> user
|
||||
- `no role` -> no user gets created
|
||||
|
||||
### URLs
|
||||
|
||||
To handle the callback and logout the urls have to be added to the urls.py:
|
||||
```python
|
||||
urlpatterns = [
|
||||
#...
|
||||
path("oidc/", include("mozilla_django_oidc.urls")),
|
||||
]
|
||||
```
|
||||
|
||||
So it should like something like this:
|
||||
```python reference
|
||||
https://github.com/zitadel/example-python-django-oidc/blob/main/mysite/urls.py#L21-L28
|
||||
```
|
||||
|
||||
## Configure and run the application
|
||||
|
||||
<Callout type="warn">
|
||||
Never store and commit secrets in the ".env" or settings.py file
|
||||
</Callout>
|
||||
|
||||
### Authentication and authorization
|
||||
|
||||
To check the authentication and authorization the views in the polls application are extended with decorators:
|
||||
|
||||
```python reference
|
||||
https://github.com/zitadel/example-python-django-oidc/blob/main/mysite/views.py
|
||||
```
|
||||
|
||||
- `@method_decorator(login_required, name="dispatch")`: means that the user has to be logged in Django, which only happens if you have one of the 3 roles("admin", "staff" or "user")
|
||||
- `@method_decorator(staff_member_required, name="dispatch")`: means you have to have at least a staff user ("admin" or "staff")
|
||||
- `/admin/`: all admin sides are only accessible if you have a superuser with the role "admin"
|
||||
|
||||
<Callout>
|
||||
Additional permission checks could be done with "permission_required" from "django.contrib.auth.decorators" also described in the [Django documentation](https://docs.djangoproject.com/en/5.0/topics/auth/customizing/#custom-permissions).
|
||||
</Callout>
|
||||
|
||||
### DB
|
||||
|
||||
Create and run migrations:
|
||||
|
||||
```bash
|
||||
python manage.py migrate
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
You can use a local Django server to test the application.
|
||||
|
||||
```bash
|
||||
python manage.py runserver
|
||||
```
|
||||
|
||||
Visit http://localhost:8000/polls or http://localhost:8000/admin and click around.
|
||||
|
||||
## Completion
|
||||
|
||||
Congratulations! You have successfully integrated your Python Django application with ZITADEL!
|
||||
|
||||
If you get stuck, consider checking out our [example](https://github.com/zitadel/example-python-django-oidc) application. This application includes all the functionalities mentioned in this quick-start. You can start by cloning the repository and defining the settings in the settings.py. If you face issues, contact us or raise an issue on [GitHub](https://github.com/zitadel/example-python-django-oidc/issues).
|
||||
|
||||
### What's next?
|
||||
|
||||
Now that you have enabled authentication, it's time for you to add more authorizations to your application using ZITADEL APIs. To do this, you can refer to the [docs](/apis/introduction) or check out the ZITADEL Management Console code on [GitHub](https://github.com/zitadel/zitadel) which uses gRPC and OpenAPI to access data.
|
||||
@@ -0,0 +1,120 @@
|
||||
---
|
||||
title: ZITADEL with React
|
||||
sidebar_label: React
|
||||
---
|
||||
|
||||
This integration guide demonstrates the recommended way to incorporate ZITADEL into your React application.
|
||||
It explains how to enable user login in your application and how to fetch data from the user info endpoint.
|
||||
|
||||
By the end of this guide, your application will have login functionality and will be able to access the current user's profile.
|
||||
|
||||
<Callout>
|
||||
This documentation references our [example](https://github.com/zitadel/zitadel-react) on GitHub.
|
||||
It also uses the @zitadel/react package with its default configuration.
|
||||
</Callout>
|
||||
|
||||
## Set up application and obtain keys
|
||||
|
||||
Before we begin developing our application, we need to perform a few configuration steps in the ZITADEL Console.
|
||||
You'll need to provide some information about your app.
|
||||
We recommend creating a new app to start from scratch.
|
||||
Navigate to your project, then add a new application at the top of the page.
|
||||
Select the **User Agent** application type and continue.
|
||||
We recommend that you use [Proof Key for Code Exchange (PKCE)](/apis/openidoauth/grant-types#proof-key-for-code-exchange) for all single page applications.
|
||||
|
||||

|
||||
|
||||
### Redirect URIs
|
||||
|
||||
The redirect URIs field tells ZITADEL where it's allowed to redirect users after authentication. For development, you can set dev mode to `true` to enable insecure HTTP and redirect to a `localhost` URI.
|
||||
The post logout redirect sends your users back to a public route on your application after they have logged out.
|
||||
|
||||
<Callout>
|
||||
If you are following along with the [example](https://github.com/zitadel/zitadel-react), set the dev mode switch to `true`.
|
||||
Configure a redirect URIs to \http://localhost:3000/callback and a post redirect URI to \http://localhost:3000/.
|
||||
</Callout>
|
||||
|
||||
Continue and create the application.
|
||||
|
||||
### Copy Client ID
|
||||
|
||||
After successful creation of the app, make sure copy the client ID, as you will need it to configure your React client.
|
||||
|
||||
## Create a project role "admin" and assign it to your user
|
||||
|
||||
Also note the projects resource ID, as you will need it to configure your React client.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
If you want to read your users roles from user info endpoint, make sure to enable the checkbox in your project.
|
||||
|
||||
## React setup
|
||||
|
||||
Now that you have configured your web application on the ZITADEL side, you can proceed with the integration of your React client.
|
||||
|
||||
### Install React dependencies
|
||||
|
||||
To conveniently connect with ZITADEL, you can install the [@zitadel/react NPM package](https://www.npmjs.com/package/@zitadel/react). Run the following command:
|
||||
|
||||
```bash
|
||||
yarn add @zitadel/react
|
||||
```
|
||||
|
||||
### Create and configure the auth service
|
||||
|
||||
The @zitadel/react package provides a `createZitadelAuth()` function which sets some defaults and initializes the underlying [oidc-client-ts](https://github.com/authts/oidc-client-ts) `UserManager` class.
|
||||
You can overwrite all the defaults with the arguments you pass to `createZitadelAuth()`.
|
||||
|
||||
Export the object returned from `createZitadelAuth()`
|
||||
|
||||
### Initialize user manager
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-react/blob/main/src/App.tsx
|
||||
```
|
||||
|
||||
### Add two new components to your application
|
||||
|
||||
First, add the component which prompts the user to login.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-react/blob/main/src/components/Login.tsx
|
||||
```
|
||||
|
||||
Then create the component for the page where the users will be redirected.
|
||||
It loads the user info endpoint once the code flow completes and prints all the information.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-react/blob/main/src/components/Callback.tsx
|
||||
```
|
||||
|
||||
You can now read a user's role to show protected areas of the application.
|
||||
|
||||
### Run
|
||||
|
||||
Finally, you can start your application by running the following:
|
||||
|
||||
```
|
||||
yarn start
|
||||
```
|
||||
|
||||
## Completion
|
||||
|
||||
Congratulations! You have successfully integrated your React application with ZITADEL!
|
||||
|
||||
If you get stuck, consider checking out the [ZITADEL React example application](https://github.com/zitadel/zitadel-react).
|
||||
This application includes all the functionalities mentioned in this quickstart.
|
||||
You can start by cloning the repository and changing the arguments to `createZitadelAuth` to fit your requirements.
|
||||
If you face issues, contact us or [raise an issue on GitHub](https://github.com/zitadel/zitadel-react/issues).
|
||||
|
||||

|
||||
|
||||
### What's next?
|
||||
|
||||
Now that you have enabled authentication, you are ready to add authorization to your application by using ZITADEL APIs.
|
||||
To do this, [refer to the API docs](/apis/introduction) or check out [the ZITADEL Management Console code on GitHub](https://github.com/zitadel/zitadel) which uses gRPC to access data.
|
||||
|
||||
For more information on how to create a React application, you can refer to [Create React App](https://github.com/facebook/create-react-app).
|
||||
If you want to learn more about the libraries wrapped by [@zitadel/react](https://www.npmjs.com/package/@zitadel/react), read the docs for [oidc-client-ts](https://github.com/authts/oidc-client-ts).
|
||||
@@ -0,0 +1,408 @@
|
||||
---
|
||||
title: ZITADEL with Symfony PHP
|
||||
sidebar_label: Symfony
|
||||
---
|
||||
|
||||
This integration guide demonstrates the recommended way to incorporate ZITADEL into your Symfony PHP application.
|
||||
It explains how to enable user login in your application and how to fetch data from the user info endpoint.
|
||||
|
||||
By the end of this guide, your application will have login functionality with basic role mapping, access the current user's profile and a user list accessible by admins.
|
||||
|
||||
<Callout>
|
||||
This documentation references our [example](https://github.com/zitadel/example-symfony-oidc) on GitHub.
|
||||
</Callout>
|
||||
|
||||
## ZITADEL setup
|
||||
|
||||
Before we can start building our application, we have to do a few configuration steps in ZITADEL Console.
|
||||
|
||||
### Project roles
|
||||
|
||||
The Example expects [user roles](/guides/integrate/retrieve-user-roles) to be returned after login.
|
||||
Symfony uses `ROLE_USER` format.
|
||||
The application will take care of upper-casing and prefixing for us.
|
||||
Inside ZITADEL, you can use regular lower-case role names without prefixes, if you prefer.
|
||||
|
||||
> Symfony automatically assigns `ROLE_USER` to any authenticated user.
|
||||
|
||||
In your project settings make sure the "Assert Roles On Authentication" is enabled.
|
||||
|
||||

|
||||
|
||||
In the project Role tab, add 2 special roles:
|
||||
|
||||
- `admin`: Assigned to users that need access to the user list.
|
||||
- `foo`: Random role for display purposes
|
||||
|
||||
A `user` role is not required. This role is assumed by default for any authenticated user in Symfony.
|
||||
|
||||

|
||||
|
||||
Finally, we can assign the roles to users in the project's authorizations tab.
|
||||
|
||||

|
||||
|
||||
### Set up application and obtain secrets
|
||||
|
||||
Next you will need to provide some information about your app.
|
||||
|
||||
In your Project, add a new application at the top of the page.
|
||||
Select Web application type and continue.
|
||||
We use [Authorization Code](/apis/openidoauth/grant-types#authorization-code)for our Symfony application.
|
||||
|
||||

|
||||
|
||||
Select `CODE` in the next step. This makes sure you still get a secret. Note that the secret never gets exposed on the browser and is therefore kept in a confidential environment. Safe the generated
|
||||
|
||||

|
||||
|
||||
With the Redirect URIs field, you tell ZITADEL where it is allowed to redirect users to after authentication. For development, you can set dev mode to `true` to enable insecure HTTP and redirect to a `localhost` URI.
|
||||
|
||||
For the example application we are writing use:
|
||||
|
||||
- `http://localhost:8000/login_check` as Redirect URI
|
||||
- `http://localhost:8000/logout` as post-logout URI.
|
||||
|
||||

|
||||
|
||||
After the final step you are presented with a client ID and secret.
|
||||
Copy and paste them to a safe location for later use by the application.
|
||||
The secret will not be displayed again, but you can regenerate one if you loose it.
|
||||
|
||||
## Setup new Symfony application
|
||||
|
||||
Now that you have configured your web application on the ZITADEL side, you can proceed with the integration of your Symfony client.
|
||||
The example is build on a [generated Symfony web app](https://symfony.com/doc/current/setup.html#creating-symfony-applications), using the following command:
|
||||
|
||||
<Callout>
|
||||
Skip this step if you are connecting ZITADEL to an existing application.
|
||||
</Callout>
|
||||
|
||||
```bash
|
||||
symfony new my_project_directory --version="7.0.*" --webapp
|
||||
cd my_project_directory
|
||||
```
|
||||
|
||||
<Callout>
|
||||
The remainder of this guide assumes a Symfony project which already includes all web app bundles, such as security, routing and ORM.
|
||||
If you are using this guide against an existing project you must make sure the required bundles are installed using the `composer require` command.
|
||||
</Callout>
|
||||
|
||||
### Install Symfony dependencies
|
||||
|
||||
To connect with ZITADEL through OpenID connect, you need to install the [Symfony OIDC bundle](https://github.com/Drenso/symfony-oidc). Run the following command:
|
||||
|
||||
```bash
|
||||
composer require drenso/symfony-oidc-bundle
|
||||
```
|
||||
|
||||
## Define the Symfony app
|
||||
|
||||
### Create a User class
|
||||
|
||||
First, we need to create a User class for the database, so we can persist user info between requests. In this case you don't need password authentication.
|
||||
Email addresses are not unique for ZITADEL users. There can be multiple user accounts with the same email address.
|
||||
See [User Constraints](/guides/manage/console/users-overview#considerations) for more details.
|
||||
We will use the User Info `sub` claim as unique "display" name for the user. `sub` equals the unique User ID from ZITADEL.
|
||||
This creates a User Repository and Entity that implements the `UserInterface`:
|
||||
|
||||
<Callout>
|
||||
You can skip this step, if you already have an existing User object in your project.
|
||||
</Callout>
|
||||
|
||||
```bash
|
||||
php bin/console make:user
|
||||
|
||||
The name of the security user class (e.g. User) [User]:
|
||||
> User
|
||||
|
||||
Do you want to store user data in the database (via Doctrine)? (yes/no) [yes]:
|
||||
> yes
|
||||
|
||||
Enter a property name that will be the unique "display" name for the user (e.g. email, username, uuid) [email]:
|
||||
> sub
|
||||
|
||||
Will this app need to hash/check user passwords? Choose No if passwords are not needed or will be checked/hashed by some other system (e.g. a single sign-on server).
|
||||
|
||||
Does this app need to hash/check user passwords? (yes/no) [yes]:
|
||||
> no
|
||||
```
|
||||
|
||||
Next, extend the User Entity with properties that we will obtain from ZITADEL and use in the application later.
|
||||
|
||||
> None of the following properties are required for authentication, but show how we can map User Info to a Symfony User Entity later. You can adjust the properties how you wish for your application.
|
||||
|
||||
```bash
|
||||
php bin/console make:entity
|
||||
|
||||
Class name of the entity to create or update (e.g. GrumpyElephant):
|
||||
> User
|
||||
|
||||
Your entity already exists! So let's add some new fields!
|
||||
|
||||
New property name (press <return> to stop adding fields):
|
||||
> display_name
|
||||
|
||||
Field type (enter ? to see all types) [string]:
|
||||
> string
|
||||
|
||||
Field length [255]:
|
||||
> 255
|
||||
|
||||
Can this field be null in the database (nullable) (yes/no) [no]:
|
||||
> yes
|
||||
|
||||
updated: src/Entity/User.php
|
||||
|
||||
Add another property? Enter the property name (or press <return> to stop adding fields):
|
||||
> full_name
|
||||
|
||||
Field type (enter ? to see all types) [string]:
|
||||
> string
|
||||
|
||||
Field length [255]:
|
||||
>
|
||||
|
||||
Can this field be null in the database (nullable) (yes/no) [no]:
|
||||
> yes
|
||||
|
||||
updated: src/Entity/User.php
|
||||
|
||||
Add another property? Enter the property name (or press <return> to stop adding fields):
|
||||
> email
|
||||
|
||||
Field type (enter ? to see all types) [string]:
|
||||
> string
|
||||
|
||||
Field length [255]:
|
||||
> 255
|
||||
|
||||
Can this field be null in the database (nullable) (yes/no) [no]:
|
||||
> yes
|
||||
|
||||
updated: src/Entity/User.php
|
||||
|
||||
Add another property? Enter the property name (or press <return> to stop adding fields):
|
||||
> email_verified
|
||||
|
||||
Field type (enter ? to see all types) [string]:
|
||||
> boolean
|
||||
|
||||
Can this field be null in the database (nullable) (yes/no) [no]:
|
||||
> yes
|
||||
|
||||
updated: src/Entity/User.php
|
||||
|
||||
Add another property? Enter the property name (or press <return> to stop adding fields):
|
||||
> created_at
|
||||
|
||||
Field type (enter ? to see all types) [datetime_immutable]:
|
||||
> datetime_immutable
|
||||
|
||||
Can this field be null in the database (nullable) (yes/no) [no]:
|
||||
> no
|
||||
|
||||
updated: src/Entity/User.php
|
||||
|
||||
Add another property? Enter the property name (or press <return> to stop adding fields):
|
||||
> updated_at
|
||||
|
||||
Field type (enter ? to see all types) [datetime_immutable]:
|
||||
> datetime_immutable
|
||||
|
||||
Can this field be null in the database (nullable) (yes/no) [no]:
|
||||
> no
|
||||
|
||||
updated: src/Entity/User.php
|
||||
|
||||
Add another property? Enter the property name (or press <return> to stop adding fields):
|
||||
>
|
||||
|
||||
Success!
|
||||
```
|
||||
|
||||
Now edit `src/Entity/User.php` to add some methods to pretty-print user data later in this example. Add import near the top of the file:
|
||||
|
||||
```php
|
||||
use DateTimeInterface;
|
||||
```
|
||||
|
||||
And extend the User class with this methods:
|
||||
|
||||
```php
|
||||
class User implements UserInterface
|
||||
{
|
||||
...
|
||||
|
||||
public function implodeRoles(): string
|
||||
{
|
||||
return implode(', ', $this->getRoles());
|
||||
}
|
||||
|
||||
public function formatCreatedAt(): string
|
||||
{
|
||||
return $this->created_at->format(DateTimeInterface::W3C);
|
||||
}
|
||||
|
||||
public function formatUpdatedAt(): string
|
||||
{
|
||||
return $this->updated_at->format(DateTimeInterface::W3C);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When you are done, the User Entity should look something like:
|
||||
|
||||
```php reference
|
||||
https://github.com/zitadel/example-symfony-oidc/blob/main/src/Entity/User.php
|
||||
```
|
||||
|
||||
Edit the User Repository to have a `findOneBySub` method, used later for OIDC User Info updates.
|
||||
|
||||
```php reference
|
||||
https://github.com/zitadel/example-symfony-oidc/blob/main/src/Repository/UserRepository.php
|
||||
```
|
||||
|
||||
### Create a Security Provider
|
||||
|
||||
Next you will need to create a Security Provider that integrates the OIDC flow between Symfony and ZITADEL.
|
||||
Create a `ZitadelUserProvider` which implements `UserProviderInterface`, `OidcUserProviderInterface` and `LoggerAwareInterface`.
|
||||
`LoggerAwareInterface` is optional if you want debug logging.
|
||||
|
||||
> We called this a `ZitadelUserProvider` because it carries a custom scope and claim mapping from ZITADEL roles to the Symfony role system.
|
||||
|
||||
```php reference
|
||||
https://github.com/zitadel/example-symfony-oidc/blob/main/src/Security/ZitadelUserProvider.php
|
||||
```
|
||||
|
||||
You can customize the User Info that is obtained and stored by adjusting the `SCOPES` constant, the `updateUserEntity` method and the User Entity.
|
||||
|
||||
### Controllers and templates
|
||||
|
||||
We need to create couple of Controllers and templates to define the app.
|
||||
|
||||
#### Index
|
||||
|
||||
The index controller serves a public page on the `/` route and provides some basic links to the authenticated sections of the app.
|
||||
|
||||
```php reference
|
||||
https://github.com/zitadel/example-symfony-oidc/blob/main/src/Controller/IndexController.php
|
||||
```
|
||||
|
||||
The index template:
|
||||
|
||||
```twig reference
|
||||
https://github.com/zitadel/example-symfony-oidc/blob/main/templates/index.html.twig
|
||||
```
|
||||
|
||||
#### Login
|
||||
|
||||
The login controller initiates the OIDC login flow by creating a Auth request and redirecting the user to ZITADEL.
|
||||
|
||||
```php reference
|
||||
https://github.com/zitadel/example-symfony-oidc/blob/main/src/Controller/LoginController.php
|
||||
```
|
||||
|
||||
#### Profile
|
||||
|
||||
The profile controller displays User Info of the currently authenticated user.
|
||||
Any authenticated user will have access to this page.
|
||||
|
||||
```php reference
|
||||
https://github.com/zitadel/example-symfony-oidc/blob/main/src/Controller/ProfileController.php
|
||||
```
|
||||
|
||||
The profile template maps the User Entity to a HTML page.
|
||||
|
||||
```twig reference
|
||||
https://github.com/zitadel/example-symfony-oidc/blob/main/templates/profile.html.twig
|
||||
```
|
||||
|
||||
#### User list
|
||||
|
||||
The user list controller displays all users from the database that were created during OIDC login.
|
||||
Only users with an administrator role will have access to this page.
|
||||
|
||||
```php reference
|
||||
https://github.com/zitadel/example-symfony-oidc/blob/main/src/Controller/UserListController.php
|
||||
```
|
||||
|
||||
```twig reference
|
||||
https://github.com/zitadel/example-symfony-oidc/blob/main/templates/user_list.html.twig
|
||||
```
|
||||
|
||||
## Configure and run the application
|
||||
|
||||
<Callout>
|
||||
Never store and commit secrets in a `.env` file. Use a `env.local` file instead and make sure the file is in `.gitignore`.
|
||||
</Callout>
|
||||
|
||||
### Database
|
||||
|
||||
Make sure you have a database configured in `.env` or `.env.local`. This example uses a local sqlite file to simplify setup:
|
||||
|
||||
```sh
|
||||
DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
|
||||
```
|
||||
|
||||
Create and run migrations:
|
||||
|
||||
```bash
|
||||
php bin/console make:migration
|
||||
php bin/console doctrine:migrations:migrate
|
||||
```
|
||||
|
||||
### Security
|
||||
|
||||
A firewall needs to be defined along with roles based access control rules.
|
||||
In the following example we define the `zitadel_user_provider` as the security class we wrote earlier. We configure the main firewall to use the `zitadel_user_provider` and listen for logout requests on the `/logout` path. We tell the oidc module to enable End Session support.
|
||||
|
||||
In the `access_control` section we protect the `/users` and `/profile` routes based on roles. Roles are mapped from ZITADEL to Symfony in the `ZitadelUserProvider` we wrote earlier.
|
||||
|
||||
```yaml reference
|
||||
https://github.com/zitadel/example-symfony-oidc/blob/main/config/packages/security.yaml
|
||||
```
|
||||
|
||||
### OIDC
|
||||
|
||||
The generated [`dresno_oidc.yaml`](https://github.com/zitadel/example-symfony-oidc/blob/main/config/packages/drenso_oidc.yaml) file can be edited to customize behavior of the OIDC bundle. For this example we stick with the default and use environment variables to connect to ZITADEL.
|
||||
|
||||
Edit `.env.local` to contain the details from the [Application setup section](#set-up-application-and-obtain-keys).
|
||||
|
||||
```sh
|
||||
OIDC_WELL_KNOWN_URL="https://tims-zitadel-instance-oj7iry.zitadel.cloud/.well-known/openid-configuration"
|
||||
OIDC_CLIENT_ID="248680248240075805@dev"
|
||||
OIDC_CLIENT_SECRET="BJPhEJULSUXseC4geqg5Yg4wWMoy7RgZKar86mbIpt8ZekC5kixMzYGcXLDeeJv7"
|
||||
```
|
||||
|
||||
> The well-known URL needs to be adjusted to your own Custom Domain.
|
||||
|
||||
Activate the route that is used as callback by the OIDC bundle:
|
||||
|
||||
```yaml reference
|
||||
https://github.com/zitadel/example-symfony-oidc/blob/main/config/routes.yaml#L6-L7
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
You can use a local Symfony server to test the application.
|
||||
|
||||
```bash
|
||||
symfony server:start --no-tls
|
||||
```
|
||||
|
||||
Visit http://localhost:8000 and click around.
|
||||
When you go to profile, you will be redirected to login your user on ZITADEL.
|
||||
After login, you should see some profile data of the current user.
|
||||
Upon clicking logout, you are redirected to the homepage.
|
||||
Now you can click "users" and log in with an account that has the administrator role.
|
||||
|
||||
## Completion
|
||||
|
||||
Congratulations! You have successfully integrated your Symfony application with ZITADEL!
|
||||
|
||||
If you get stuck, consider checking out our [example](https://github.com/zitadel/example-symfony-oidc) application. This application includes all the functionalities mentioned in this quick-start. You can start by cloning the repository and defining a `.env.local` with your settings. If you face issues, contact us or raise an issue on [GitHub](https://github.com/zitadel/example-symfony-oidc/issues).
|
||||
|
||||
### What's next?
|
||||
|
||||
Now that you have enabled authentication, it's time for you to add more authorizations to your application using ZITADEL APIs. To do this, you can refer to the [docs](/apis/introduction) or check out the ZITADEL Management Console code on [GitHub](https://github.com/zitadel/zitadel) which uses gRPC and OpenAPI to access data.
|
||||
@@ -0,0 +1,129 @@
|
||||
---
|
||||
title: ZITADEL with Vue
|
||||
sidebar_label: Vue
|
||||
---
|
||||
|
||||
This integration guide demonstrates the recommended way to incorporate ZITADEL into your Vue application.
|
||||
It explains how to enable user login in your application and how to fetch data from the user info endpoint.
|
||||
|
||||
By the end of this guide, your application will have login functionality and will be able to access the current user's profile.
|
||||
|
||||
<Callout title="">
|
||||
This documentation references our [example](https://github.com/zitadel/zitadel-vue) on GitHub.
|
||||
It also uses the @zitadel/vue package with its default configuration.
|
||||
</Callout>
|
||||
|
||||
## Set up application and obtain keys
|
||||
|
||||
Before we begin developing our application, we need to perform a few configuration steps in the ZITADEL Management Console.
|
||||
You'll need to provide some information about your app.
|
||||
We recommend creating a new app to start from scratch.
|
||||
Navigate to your project, then add a new application at the top of the page.
|
||||
Select the **User Agent** application type and continue.
|
||||
We recommend that you use [Proof Key for Code Exchange (PKCE)](/apis/openidoauth/grant-types#proof-key-for-code-exchange) for all single page applications.
|
||||
|
||||

|
||||
|
||||
### Redirect URIs
|
||||
|
||||
The redirect URIs field tells ZITADEL where it's allowed to redirect users after authentication. For development, you can set dev mode to `true` to enable insecure HTTP and redirect to a `localhost` URI.
|
||||
The post logout redirect sends your users back to a public route on your application after they have logged out.
|
||||
|
||||
<Callout>
|
||||
If you are following along with the [example](https://github.com/zitadel/zitadel-vue), set the dev mode switch to `true`.
|
||||
Configure a redirect URIs to *http:/<span></span>/localhost:5173/auth/signinwin/zitadel* and a post redirect URI to *http:/<span></span>/localhost:5173/*.
|
||||
</Callout>
|
||||
|
||||
Continue and create the application.
|
||||
|
||||
### Refresh Token and Client ID
|
||||
|
||||
After successful creation of the app, make sure you tick the checkbox to enable refresh tokens.
|
||||
Also copy the client ID, as you will need it to configure your Vue client.
|
||||
|
||||

|
||||
|
||||
## Create a project role "admin" and assign it to your user
|
||||
|
||||
Also note the projects resource ID, as you will need it to configure your Vue client.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Vue setup
|
||||
|
||||
Now that you have configured your web application on the ZITADEL side, you can proceed with the integration of your Vue client.
|
||||
|
||||
### Install Vue dependencies
|
||||
|
||||
To conveniently connect with ZITADEL, you can install the [@zitadel/vue NPM package](https://www.npmjs.com/package/@zitadel/vue). Run the following command:
|
||||
|
||||
```bash
|
||||
npm install --save @zitadel/vue
|
||||
```
|
||||
|
||||
### Create and configure the auth service
|
||||
|
||||
The @zitadel/vue package provides a `createZITADELAuth()` function which sets some defaults and calls the underlying [vue-oidc-client packages](https://github.com/soukoku/vue-oidc-client) `createOidcAuth()` function.
|
||||
You can overwrite all the defaults with the arguments you pass to `createZITADELAuth()`.
|
||||
|
||||
Export the object returned from `createZITADELAuth()`
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-vue/blob/main/src/services/zitadelAuth.ts
|
||||
```
|
||||
|
||||
### Register the auth service in your global variables when bootstrapping Vue
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-vue/blob/main/src/main.ts
|
||||
```
|
||||
|
||||
### Add three new views to your application
|
||||
|
||||
The restricted admin view will only be shown if the user is authenticated and has the role "admin" in the apps project in ZITADEL.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-vue/blob/main/src/views/AdminView.vue
|
||||
```
|
||||
|
||||
The restricted login view is shown to all authenticated users.
|
||||
It prints all the information it gets from the token and from the user info endpoint.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-vue/blob/main/src/views/LoginView.vue
|
||||
```
|
||||
|
||||
The public no access view is shown to authenticated users who navigate to a page they don't have access to based on their roles.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-vue/blob/main/src/views/NoAccessView.vue
|
||||
```
|
||||
|
||||
### Add protected routes to your new pages as well as a Signout link
|
||||
|
||||
Note that we conditionally render the admin view or the no access view based on the user's roles.
|
||||
|
||||
```ts reference
|
||||
https://github.com/zitadel/zitadel-vue/blob/main/src/router/index.ts
|
||||
```
|
||||
|
||||
## Completion
|
||||
|
||||
Congratulations! You have successfully integrated your Vue application with ZITADEL!
|
||||
|
||||
If you get stuck, consider checking out the [ZITADEL Vue example application](https://github.com/zitadel/zitadel-vue).
|
||||
This application includes all the functionalities mentioned in this quickstart.
|
||||
You can start by cloning the repository and change the arguments to createZITADELAuth so they fit your requirements.
|
||||
If you face issues, contact us or [raise an issue on GitHub](https://github.com/zitadel/zitadel-vue/issues).
|
||||
|
||||

|
||||
|
||||
### What's next?
|
||||
|
||||
Now that you have enabled authentication, you are ready to call add authorization to your application using ZITADEL APIs.
|
||||
To do this, [refer to the API docs](/apis/introduction) or check out [the ZITADEL Management Console code on GitHub](https://github.com/zitadel/zitadel) which uses gRPC to access data.
|
||||
|
||||
For more information on how to create an Vue application, you can refer to [Vue](https://vuejs.org/guide/quick-start.html).
|
||||
If you want to learn more about the libraries wrapped by [@zitadel/vue](https://www.npmjs.com/package/@zitadel/vue), [read the docs for vue-oidc-client](https://github.com/soukoku/vue-oidc-client/wiki/V1-Docs).
|
||||
@@ -0,0 +1,244 @@
|
||||
---
|
||||
title: ZITADEL with Go
|
||||
sidebar_label: Go
|
||||
---
|
||||
|
||||
This integration guide shows you how to integrate **ZITADEL** into your Go API. It demonstrates how to secure your API using
|
||||
OAuth 2 Token Introspection.
|
||||
|
||||
> ℹ️ These examples and guides are based on our official [Go SDK](https://github.com/zitadel/zitadel-go).
|
||||
>
|
||||
> The SDK is a convenient wrapper around our low-level [OIDC library](https://github.com/zitadel/oidc). For most use cases, using the helpers provided in our [Go SDK](https://github.com/zitadel/zitadel-go) is the recommended approach for implementing authentication.
|
||||
|
||||
At the end of the guide you should have an API with a protected endpoint.
|
||||
|
||||
> This documentation references our HTTP example. There's also one for GRPC. Check them out on [GitHub](https://github.com/zitadel/zitadel-go/blob/next/example/api/http/main.go).
|
||||
|
||||
## Prerequisites
|
||||
|
||||
This will handle the OAuth 2.0 introspection request including authentication using JWT with Private Key using our [Go SDK](https://github.com/zitadel/zitadel-go).
|
||||
All that is required, is to create your API, create a private key and a personal access token for a service user.
|
||||
|
||||
### Set up application and obtain keys
|
||||
|
||||
Before we begin developing our API, we need to perform a few configuration steps in the ZITADEL Console.
|
||||
You'll need to provide some information about your app. We recommend creating a new app to start from scratch.
|
||||
|
||||
Starting from the homepage of your management console, click on Create Application
|
||||
|
||||

|
||||
|
||||
Select a project from the dropdown and select *Other* as framework, then continue.
|
||||
|
||||

|
||||
|
||||
Add your app name and select *API* as application type, then continue.
|
||||
|
||||

|
||||
|
||||
We recommend that you use JWT Profile for authenticating at the Introspection Endpoint. So select *JWT* as authentication method
|
||||
|
||||

|
||||
|
||||
You then need to create a new JSON key.
|
||||
|
||||

|
||||
|
||||
Select an expiration date that suits you.
|
||||
|
||||

|
||||
|
||||
And make sure to download it, as you won't be able to retrieve it again.
|
||||
|
||||

|
||||
|
||||
Now we need to create a *Personal Access Token* to authenticate the client requests.
|
||||
|
||||
On the user view, switch to *Service Users* and create a new one.
|
||||
|
||||

|
||||
|
||||
Give the service user a name and a user name. Select `Bearer` as *Access Token Type*.
|
||||
|
||||

|
||||
|
||||
### Create service user and personal access token (PAT)
|
||||
|
||||
Once done, from the left panel of the user management, click on Personal Access Token and create a new one.
|
||||
|
||||

|
||||
|
||||
Set an expiration date and then copy the PAT generated to somewhere safe. We will need it later.
|
||||
|
||||

|
||||
|
||||
## Go Setup
|
||||
|
||||
### Add Go SDK to your project
|
||||
|
||||
You need to add the [SDK](https://github.com/zitadel/zitadel-go) into Go Modules by:
|
||||
|
||||
```bash
|
||||
go get -u github.com/zitadel/zitadel-go/v3
|
||||
```
|
||||
|
||||
### Create example API
|
||||
|
||||
Create a new go file with the content below. This will create an API with three endpoints:
|
||||
- `/api/healthz`: can be called by anyone and always returns `OK`
|
||||
- `/api/tasks`: requires authorization and returns the available tasks
|
||||
- `/api/add-task`: requires authorization with granted `admin` role and adds the task to the list
|
||||
|
||||
If authorization is required, the token must not be expired and the API has to be part of the audience (either client_id or project_id).
|
||||
|
||||
For tests we will use a Personal Access Token.
|
||||
|
||||
```go reference
|
||||
https://github.com/zitadel/zitadel-go/blob/next/example/api/http/main.go
|
||||
```
|
||||
|
||||
You will need to provide some values for the program to run:
|
||||
- `domain`: Your ZITADEL Custom Domain, e.g. https://my-domain.zitadel.cloud
|
||||
- `key`: The path to the downloaded key.json
|
||||
- `port`: The port on which the API will be accessible, default it 8089
|
||||
|
||||
## Test API
|
||||
|
||||
After you have configured everything correctly, you can simply start the example by:
|
||||
|
||||
```bash
|
||||
go run main.go --domain <custom domain> --key <path>
|
||||
```
|
||||
|
||||
This could look like:
|
||||
|
||||
```bash
|
||||
go run main.go --domain my-domain.zitadel.cloud --key ./api.json
|
||||
```
|
||||
|
||||
After you get a successful log:
|
||||
```
|
||||
2023/12/04 10:27:42 INFO server listening, press ctrl+c to stop addr=http://localhost:8089
|
||||
```
|
||||
|
||||
### Public endpoint
|
||||
|
||||
Now you can call the API by browser or curl. Try the healthz endpoint first:
|
||||
|
||||
```bash
|
||||
curl -i http://localhost:8089/api/healthz
|
||||
```
|
||||
|
||||
it should return something like:
|
||||
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
Date: Mon, 04 Dec 2023 09:29:38 GMT
|
||||
Content-Length: 4
|
||||
|
||||
"OK"
|
||||
```
|
||||
|
||||
### Task list
|
||||
|
||||
and the task list endpoint:
|
||||
|
||||
```bash
|
||||
curl -i http://localhost:8089/api/tasks
|
||||
```
|
||||
|
||||
it will return:
|
||||
|
||||
```
|
||||
HTTP/1.1 401 Unauthorized
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
X-Content-Type-Options: nosniff
|
||||
Date: Mon, 04 Dec 2023 09:41:54 GMT
|
||||
Content-Length: 44
|
||||
|
||||
unauthorized: authorization header is empty
|
||||
```
|
||||
|
||||
We need to use the personal access token generated previously.
|
||||
|
||||
If you provide a valid Bearer Token:
|
||||
|
||||
```bash
|
||||
curl -i -H "Authorization: Bearer ${token}" http://localhost:8089/api/tasks
|
||||
```
|
||||
|
||||
it will return an empty list:
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
Date: Mon, 04 Dec 2023 09:49:06 GMT
|
||||
Content-Length: 2
|
||||
|
||||
{}
|
||||
```
|
||||
|
||||
### Try to add a new task
|
||||
|
||||
Let's see what happens if you call the AddTask endpoint:
|
||||
|
||||
```bash
|
||||
curl -i -H "Authorization: Bearer ${token}" http://localhost:8089/api/add-task
|
||||
```
|
||||
|
||||
it will complain about the missing `admin` role:
|
||||
```
|
||||
HTTP/1.1 403 Forbidden
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
X-Content-Type-Options: nosniff
|
||||
Date: Mon, 04 Dec 2023 09:52:00 GMT
|
||||
Content-Length: 50
|
||||
|
||||
permission denied: missing required role: `admin`
|
||||
```
|
||||
|
||||
### Add administrator role
|
||||
|
||||
So let's create the role and grant it to the user. To do so, go to your project in ZITADEL Management Console
|
||||
and create the role by selecting `Roles` in the navigation and then clicking on the `New Role` button.
|
||||
Finally, create the role as shown below:
|
||||
|
||||

|
||||
|
||||
After you have created the role, let's grant it the user, who requested the tasks.
|
||||
Click on `Authorization` in the navigation and create a new one by selecting the user and the `admin` role.
|
||||
After successful creation, it should look like:
|
||||
|
||||

|
||||
|
||||
So you should now be able to add a new task:
|
||||
|
||||
```bash
|
||||
curl -i -H "Authorization: Bearer ${token}" http://localhost:8089/api/add-task --data "task=My new task"
|
||||
```
|
||||
|
||||
which will report back the successful addition:
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
Date: Mon, 04 Dec 2023 10:06:29 GMT
|
||||
Content-Length: 26
|
||||
|
||||
"task `My new task` added"
|
||||
```
|
||||
|
||||
Let's now retrieve the task list again:
|
||||
|
||||
```bash
|
||||
curl -i -H "Authorization: Bearer ${token}" http://localhost:8089/api/tasks
|
||||
```
|
||||
|
||||
As you can see your new task ist listed. And since you're an `admin` now, you will always get an additional `create a new task on /api/add-task`:
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json
|
||||
Date: Mon, 04 Dec 2023 10:08:38 GMT
|
||||
Content-Length: 62
|
||||
|
||||
{"tasks":["My new task","create a new task on /api/add-task"]}
|
||||
```
|
||||
@@ -0,0 +1,283 @@
|
||||
---
|
||||
title: ZITADEL with Java Spring Boot
|
||||
sidebar_label: Java Spring Boot
|
||||
---
|
||||
|
||||
This integration guide shows you how to integrate **ZITADEL** into your Java Spring Boot API. It demonstrates how to secure your API using
|
||||
OAuth 2 Token Introspection.
|
||||
|
||||
At the end of the guide you should have an API with a protected endpoint.
|
||||
|
||||
<Callout>
|
||||
This documentation references our [example](https://github.com/zitadel/zitadel-java) on GitHub.
|
||||
You can either create your own application or directly run the example by providing the necessary arguments.
|
||||
</Callout>
|
||||
|
||||
## Set up application
|
||||
|
||||
Before we begin developing our API, we need to perform a few configuration steps in the ZITADEL Console.
|
||||
You'll need to provide some information about your app. We recommend creating a new app to start from scratch. Navigate to your Project, then add a new application at the top of the page.
|
||||
Select the **API** application type and continue.
|
||||
|
||||

|
||||
|
||||
Select Basic Auth for authenticating at the Introspection Endpoint.
|
||||
|
||||

|
||||
|
||||
After successful creation of the app, a pop-up will appear displaying the app's client ID. Copy the client ID and secret, as you will need it to configure your Java client.
|
||||
|
||||

|
||||
|
||||
## Spring Setup
|
||||
|
||||
Now that you have configured your web application on the ZITADEL side, you can proceed with the integration of your Spring client.
|
||||
This guide will reference the [example repository](https://github.com/zitadel/zitadel-java) and explain the necessary steps taken in there.
|
||||
If your starting from scratch, you can use the Spring Initializer with the [following setup](https://start.spring.io/#!type=maven-project&language=java&platformVersion=3.2.1&packaging=jar&jvmVersion=17&dependencies=web,lombok,oauth2-resource-server) as a base.
|
||||
|
||||
### Support class
|
||||
|
||||
To be able to take the most out of ZITADELs RBAC, we first need to create a CustomAuthorityOpaqueTokenIntrospector, that will
|
||||
customize the introspection behavior and map the role claims (`urn:zitadel:iam:org:project:roles`)
|
||||
into Spring Security `authiorities`, which can be used later on to determine the granted permissions.
|
||||
|
||||
So in your application, create a `support/zitadel` package and in there the `CustomAuthorityOpaqueTokenIntrospector.java`:
|
||||
|
||||
```java reference
|
||||
https://github.com/zitadel/zitadel-java/blob/main/api/src/main/java/demo/app/support/zitadel/CustomAuthorityOpaqueTokenIntrospector.java
|
||||
```
|
||||
|
||||
### Application server configuration
|
||||
|
||||
As we have now our support class, we can now create and configure the application server itself.
|
||||
|
||||
In a new `config` package, create the `WebSecurityConfig.java`.
|
||||
This class will take care of the authorization by require the calls on `/api/tasks` to be authorized. Any other endpoint will be public by default.
|
||||
It will also use the just created CustomAuthorityOpaqueTokenIntrospector for the introspection call:
|
||||
|
||||
```java reference
|
||||
https://github.com/zitadel/zitadel-java/blob/main/api/src/main/java/demo/app/config/WebSecurityConfig.java
|
||||
```
|
||||
|
||||
For the authorization (and the server in general) to work, the application needs some configuration, so please provide the following to your `application.yml` (resources folder):
|
||||
|
||||
```yaml reference
|
||||
https://github.com/zitadel/zitadel-java/blob/main/api/src/main/resources/application.yml
|
||||
```
|
||||
|
||||
Note that the `introspection-uri`, `client-id` and `client-secret` are only placeholders. You can either change them in here using the values provided by ZITADEL
|
||||
or pass them later on as arguments when starting the application.
|
||||
|
||||
### Create example API
|
||||
|
||||
Create a `api` package with a `ExampleController.java` file with the content below. This will create an API with three endpoints / methods:
|
||||
- `/api/healthz`: can be called by anyone and always returns `OK`
|
||||
- `/api/tasks (GET)`: requires authorization and returns the available tasks
|
||||
- `/api/tasks (POST)`: requires authorization with granted `admin` role and adds the task to the list
|
||||
|
||||
If authorization is required, the token must not be expired and the API has to be part of the audience (either client_id or project_id).
|
||||
|
||||
For tests we will use a Personal Access Token or the [Java Spring web example](../login/java-spring).
|
||||
|
||||
```java reference
|
||||
https://github.com/zitadel/zitadel-java/blob/main/api/src/main/java/demo/app/api/ExampleController.java
|
||||
```
|
||||
|
||||
## Test API
|
||||
|
||||
In case you've created your own application and depending on your development setup you might need to build the application first:
|
||||
|
||||
```bash
|
||||
mvn clean package -DskipTests
|
||||
```
|
||||
|
||||
You will need to provide the `introspection-uri` ($CUSTOM_DOMAIN/oauth/v2/introspect), the `client-id` and `client-secret` previously created:
|
||||
|
||||
```bash
|
||||
java \
|
||||
-Dspring.security.oauth2.resourceserver.opaquetoken.introspection-uri=<see configuration above> \
|
||||
-Dspring.security.oauth2.resourceserver.opaquetoken.client-id=<see configuration above> \
|
||||
-Dspring.security.oauth2.resourceserver.opaquetoken.client-secret=<see configuration above> \
|
||||
-jar api/target/api-0.0.2-SNAPSHOT.jar
|
||||
```
|
||||
|
||||
This could look like:
|
||||
|
||||
```bash
|
||||
java \
|
||||
-Dspring.security.oauth2.resourceserver.opaquetoken.introspection-uri=https://my-domain.zitadel.cloud/oauth/v2/introspect \
|
||||
-Dspring.security.oauth2.resourceserver.opaquetoken.client-id=243861220627644836@example \
|
||||
-Dspring.security.oauth2.resourceserver.opaquetoken.client-secret=WJKLF3kfPOi3optkg9vi3jmfjv8oj32nfiäohj!FSC09RWUSR \
|
||||
-jar web/target/web-0.0.2-SNAPSHOT.jar
|
||||
```
|
||||
|
||||
### Public endpoint
|
||||
|
||||
Now you can call the API by browser or curl. Try the healthz endpoint first:
|
||||
|
||||
```bash
|
||||
curl -i http://localhost:18090/api/healthz
|
||||
```
|
||||
|
||||
it should return something like:
|
||||
|
||||
```
|
||||
HTTP/1.1 200
|
||||
Vary: Origin
|
||||
Vary: Access-Control-Request-Method
|
||||
Vary: Access-Control-Request-Headers
|
||||
X-Content-Type-Options: nosniff
|
||||
X-XSS-Protection: 0
|
||||
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
|
||||
Pragma: no-cache
|
||||
Expires: 0
|
||||
X-Frame-Options: DENY
|
||||
Content-Type: text/plain;charset=UTF-8
|
||||
Content-Length: 2
|
||||
Date: Mon, 15 Jan 2024 09:07:21 GMT
|
||||
|
||||
OK
|
||||
```
|
||||
|
||||
### Task list
|
||||
|
||||
and the task list endpoint:
|
||||
|
||||
```bash
|
||||
curl -i http://localhost:18090/api/tasks
|
||||
```
|
||||
|
||||
it will return:
|
||||
|
||||
```
|
||||
HTTP/1.1 401
|
||||
Vary: Origin
|
||||
Vary: Access-Control-Request-Method
|
||||
Vary: Access-Control-Request-Headers
|
||||
WWW-Authenticate: Bearer
|
||||
X-Content-Type-Options: nosniff
|
||||
X-XSS-Protection: 0
|
||||
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
|
||||
Pragma: no-cache
|
||||
Expires: 0
|
||||
X-Frame-Options: DENY
|
||||
Content-Length: 0
|
||||
Date: Mon, 15 Jan 2024 09:07:55 GMT
|
||||
```
|
||||
|
||||
Get a valid access_token for the API. You can either achieve this by getting an access token with the project_id in the audience
|
||||
(e.g. by using the [Spring Boot web example](../login/java-spring)) use a PAT of a service account.
|
||||
|
||||
If you provide a valid Bearer Token:
|
||||
|
||||
```bash
|
||||
curl -i -H "Authorization: Bearer ${token}" http://localhost:18090/api/tasks
|
||||
```
|
||||
|
||||
it will return an empty list:
|
||||
```
|
||||
HTTP/1.1 200
|
||||
Vary: Origin
|
||||
Vary: Access-Control-Request-Method
|
||||
Vary: Access-Control-Request-Headers
|
||||
X-Content-Type-Options: nosniff
|
||||
X-XSS-Protection: 0
|
||||
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
|
||||
Pragma: no-cache
|
||||
Expires: 0
|
||||
X-Frame-Options: DENY
|
||||
Content-Type: application/json
|
||||
Transfer-Encoding: chunked
|
||||
Date: Mon, 15 Jan 2024 09:15:10 GMT
|
||||
|
||||
[]
|
||||
```
|
||||
|
||||
### Try to add a new task
|
||||
|
||||
Let's see what happens if you call the tasks endpoint:
|
||||
|
||||
```bash
|
||||
curl -i -X POST -H "Authorization: Bearer ${token}" -H "Content-Type: application/json" --data 'my new task' http://localhost:18090/api/tasks
|
||||
```
|
||||
|
||||
it will complain with a permission denied (missing `admin` role):
|
||||
```
|
||||
HTTP/1.1 403
|
||||
Vary: Origin
|
||||
Vary: Access-Control-Request-Method
|
||||
Vary: Access-Control-Request-Headers
|
||||
WWW-Authenticate: Bearer error="insufficient_scope", error_description="The request requires higher privileges than provided by the access token.", error_uri="https://tools.ietf.org/html/rfc6750#section-3.1"
|
||||
X-Content-Type-Options: nosniff
|
||||
X-XSS-Protection: 0
|
||||
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
|
||||
Pragma: no-cache
|
||||
Expires: 0
|
||||
X-Frame-Options: DENY
|
||||
Content-Length: 0
|
||||
Date: Mon, 15 Jan 2024 09:24:39 GMT
|
||||
```
|
||||
|
||||
### Add administrator role
|
||||
|
||||
So let's create the role and grant it to the user. To do so, go to your project in ZITADEL Management Console
|
||||
and create the role by selecting `Roles` in the navigation and then clicking on the `New Role` button.
|
||||
Finally, create the role as shown below:
|
||||
|
||||

|
||||
|
||||
After you have created the role, let's grant it the user, who requested the tasks.
|
||||
Click on `Authorization` in the navigation and create a new one by selecting the user and the `admin` role.
|
||||
After successful creation, it should look like:
|
||||
|
||||

|
||||
|
||||
So you should now be able to add a new task:
|
||||
|
||||
```bash
|
||||
curl -i -X POST -H "Authorization: Bearer ${token}" -H "Content-Type: application/json" --data 'my new task' http://localhost:18090/api/tasks
|
||||
```
|
||||
|
||||
which will report back the successful addition:
|
||||
```
|
||||
HTTP/1.1 200
|
||||
Vary: Origin
|
||||
Vary: Access-Control-Request-Method
|
||||
Vary: Access-Control-Request-Headers
|
||||
X-Content-Type-Options: nosniff
|
||||
X-XSS-Protection: 0
|
||||
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
|
||||
Pragma: no-cache
|
||||
Expires: 0
|
||||
X-Frame-Options: DENY
|
||||
Content-Type: application/json
|
||||
Content-Length: 10
|
||||
Date: Mon, 15 Jan 2024 09:26:11 GMT
|
||||
|
||||
task added
|
||||
```
|
||||
|
||||
Let's now retrieve the task list again:
|
||||
|
||||
```bash
|
||||
curl -i -H "Authorization: Bearer ${token}" http://localhost:18090/api/tasks
|
||||
```
|
||||
|
||||
As you can see your new task is listed:
|
||||
```
|
||||
HTTP/1.1 200
|
||||
Vary: Origin
|
||||
Vary: Access-Control-Request-Method
|
||||
Vary: Access-Control-Request-Headers
|
||||
X-Content-Type-Options: nosniff
|
||||
X-XSS-Protection: 0
|
||||
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
|
||||
Pragma: no-cache
|
||||
Expires: 0
|
||||
X-Frame-Options: DENY
|
||||
Content-Type: application/json
|
||||
Transfer-Encoding: chunked
|
||||
Date: Mon, 15 Jan 2024 09:26:48 GMT
|
||||
|
||||
["my new task"]
|
||||
```
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
title: ZITADEL with Node.js
|
||||
sidebar_label: NestJS
|
||||
---
|
||||
|
||||
# ZITADEL with Node.js (NestJS)
|
||||
|
||||
This documentation section guides you through the process of integrating ZITADEL into your Node.js backend using the NestJS framework. The provided example demonstrates authentication using an OIDC (OAuth2) token introspection strategy with a ZITADEL service account for machine-to-machine communication.
|
||||
|
||||
## Overview
|
||||
|
||||
The NestJS API includes a single secured route that prints "Hello World!" when authenticated. The API expects an authorization header with a valid JWT, serving as a bearer token to authenticate the user when calling the API. The API will validate the access token on the [introspect endpoint](/apis/openidoauth/endpoints#introspection-endpoint) and receive the user from ZITADEL.
|
||||
|
||||
The API application utilizes [JWT with Private Key](/apis/openidoauth/authn-methods#jwt-with-private-key) for authentication against ZITADEL and accessing the introspection endpoint. Make sure to create an API Application within Zitadel and download the JSON. In this instance, we use this service account, so make sure to provide the secrets in the example application via environmental variables.
|
||||
|
||||
## Overview
|
||||
|
||||
The NestJS API includes a private endpoint `GET http://localhost:${APP_PORT}/api/v1/app`, which returns "Hello World" when authenticated. The authentication is performed using a JWT obtained through the token introspection strategy.
|
||||
|
||||
## Running the Example
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Make sure you have Node.js and npm installed on your machine.
|
||||
|
||||
### ZITADEL Configuration for the API
|
||||
|
||||
1. Create a ZITADEL instance and a project by following the steps [here](/guides/start/quickstart#3-create-your-zitadel-instance).
|
||||
|
||||
2. Set up an API application within your project:
|
||||
- Create a new application of type "API" with authentication method "Private Key".
|
||||
- Create a and save the Private Key JSON file.
|
||||
|
||||
### Create and Run the API
|
||||
|
||||
Clone or download the [example repository](https://github.com/ehwplus/zitadel-nodejs-nestjs):
|
||||
|
||||
```bash
|
||||
git clone https://github.com/ehwplus/zitadel-nodejs-nestjs && cd zitadel-nodejs-nestjs
|
||||
```
|
||||
|
||||
and follow the instructions here: https://github.com/ehwplus/zitadel-nodejs-nestjs/blob/main/README.md#installation
|
||||
|
||||
### Test the API
|
||||
|
||||
Call the API without authorization headers:
|
||||
|
||||
```bash
|
||||
curl --request GET \
|
||||
--url http://localhost:${APP_PORT}/api/v1/app
|
||||
```
|
||||
|
||||
You should get a response with Status Code 401 and an error message.
|
||||
|
||||
Now, add an authorization header with a valid JWT obtained through ZITADEL:
|
||||
|
||||
```bash
|
||||
export JWT=your-valid-jwt
|
||||
|
||||
curl --request GET \
|
||||
--url http://localhost:${APP_PORT}/api/v1/app \
|
||||
--header "authorization: Bearer $JWT"
|
||||
```
|
||||
|
||||
You should now receive a response with Status Code 200 and the message:
|
||||
|
||||
```json
|
||||
"Hello World!"
|
||||
```
|
||||
|
||||
Congratulations! You have successfully integrated ZITADEL authentication into your NestJS API using the Token Introspection strategy.
|
||||
@@ -0,0 +1,306 @@
|
||||
---
|
||||
title: ZITADEL with Pylon
|
||||
sidebar_label: Pylon
|
||||
---
|
||||
|
||||
import AppJWT from "../imports/_app_jwt.mdx";
|
||||
import ServiceuserJWT from "../imports/_serviceuser_jwt.mdx";
|
||||
import ServiceuserRole from "../imports/_serviceuser_role.mdx";
|
||||
|
||||
This integration guide demonstrates the recommended way to incorporate ZITADEL into your [Pylon](https://pylon.cronit.io) service.
|
||||
It explains how to check the token validity in the API and how to check for permissions.
|
||||
|
||||
By the end of this guide, your application will have three different endpoint which are public, private(valid token) and private-scoped(valid token with specific role).
|
||||
|
||||
## ZITADEL setup
|
||||
|
||||
Before we can start building our application, we have to do a few configuration steps in ZITADEL Management Console.
|
||||
|
||||
### Create application
|
||||
|
||||
<AppJWT components={props.components} />
|
||||
|
||||
### Create Serviceuser
|
||||
|
||||
<ServiceuserJWT components={props.components} />
|
||||
|
||||
### Give Serviceuser an authorization
|
||||
|
||||
<ServiceuserRole components={props.components} />
|
||||
|
||||
### Prerequisites
|
||||
|
||||
At the end you should have the following for the API:
|
||||
|
||||
- Issuer, something like `https://example.zitadel.cloud` or `http://localhost:8080`
|
||||
- `.json`-key-file for the API, from the application
|
||||
- ID of the project
|
||||
|
||||
And the following from the Serviceuser:
|
||||
|
||||
- `.json`-key-file from the serviceuser
|
||||
|
||||
## Setup new Pylon service
|
||||
|
||||
Pylon allows you to create a new service using the `npm create pylon` command. This command creates a new Pylon project with a basic project structure and configuration.
|
||||
During the setup process, you can choose your preferred runtime, such as Bun, Node.js, or Cloudflare Workers.
|
||||
|
||||
**This guide uses the Bun runtime.**
|
||||
|
||||
### Creating a new project
|
||||
|
||||
To create a new Pylon project, run the following command:
|
||||
|
||||
```bash
|
||||
npm create pylon my-pylon@latest
|
||||
```
|
||||
|
||||
This will create a new directory called `my-pylon` with a basic Pylon project structure.
|
||||
|
||||
### Project structure
|
||||
|
||||
Pylon projects are structured as follows:
|
||||
|
||||
```
|
||||
my-pylon/
|
||||
├── .pylon/
|
||||
├── src/
|
||||
│ ├── index.ts
|
||||
├── package.json
|
||||
├── tsconfig.json
|
||||
```
|
||||
|
||||
- `.pylon/`: Contains the production build of your project.
|
||||
- `src/`: Contains the source code of your project.
|
||||
- `src/index.ts`: The entry point of your Pylon service.
|
||||
- `package.json`: The npm package configuration file.
|
||||
- `tsconfig.json`: The TypeScript configuration file.
|
||||
|
||||
### Basic example
|
||||
|
||||
Here's an example of a basic Pylon service:
|
||||
|
||||
```ts
|
||||
|
||||
export const graphql = {
|
||||
Query: {
|
||||
sum: (a: number, b: number) => a + b,
|
||||
},
|
||||
Mutation: {
|
||||
divide: (a: number, b: number) => a / b,
|
||||
},
|
||||
};
|
||||
|
||||
export default app;
|
||||
```
|
||||
|
||||
## Secure the API
|
||||
|
||||
### Add ZITADEL info to the service
|
||||
|
||||
1. Create a `.env` file in the root folder of your project and add the following configuration:
|
||||
|
||||
```bash
|
||||
AUTH_ISSUER='URL to the zitadel instance'
|
||||
AUTH_PROJECT_ID='ID of the project'
|
||||
```
|
||||
|
||||
It should look something like this:
|
||||
|
||||
```bash
|
||||
AUTH_ISSUER='https://example.zitadel.cloud'
|
||||
AUTH_PROJECT_ID='250719519163548112'
|
||||
```
|
||||
|
||||
2. Copy the `.json`-key-file that you downloaded from the ZITADEL Management Console into the root folder of your project and rename it to `key.json`.
|
||||
|
||||
3. (Optional) For added convenience in production environments, you can include the content of the .json key file as `AUTH_KEY` in the .env file or as an environment variable.
|
||||
|
||||
### Auth
|
||||
|
||||
Pylon provides a auth module and a decorator to check the validity of the token and the permissions.
|
||||
|
||||
- `auth.initialize()`: Initializes the authentication middleware.
|
||||
- `auth.require()` : Middleware to check if the token is valid.
|
||||
- `auth.require({roles: ['role']})`: Middleware to check if the token is valid and has the specified roles.
|
||||
- `requireAuth()`: Decorator to check if the token is valid.
|
||||
- `requireAuth({roles: ['role']})`: Decorator to check if the token is valid and has the specified roles.
|
||||
|
||||
### Build the Pylon service
|
||||
|
||||
Now we will create a new Pylon service with the following endpoints:
|
||||
|
||||
- `/api/public`: Public endpoint
|
||||
- `/api/private`: Private endpoint
|
||||
- `/api/private-scoped`: Private endpoint with specific role
|
||||
- `/graphql`: GraphQL endpoint
|
||||
- Query: `me`: Private endpoint that returns the current user and the messages if the role is `read:messages`
|
||||
- Query: `info`: Public endpoint
|
||||
|
||||
### Create the service
|
||||
|
||||
The following code demonstrates how to create a Pylon service with the required endpoints, it must be added to the `src/index.ts` file of your project:
|
||||
|
||||
```ts
|
||||
import {
|
||||
app,
|
||||
auth,
|
||||
requireAuth,
|
||||
getContext,
|
||||
ServiceError,
|
||||
} from "@getcronit/pylon";
|
||||
|
||||
class User {
|
||||
id: string;
|
||||
name: string;
|
||||
#messages: string[];
|
||||
|
||||
constructor(id: string, name: string, messages: string[]) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.#messages = messages;
|
||||
}
|
||||
|
||||
@requireAuth({ roles: ["read:messages"] })
|
||||
async messages() {
|
||||
return this.#messages;
|
||||
}
|
||||
|
||||
static users: User[] = [];
|
||||
|
||||
@requireAuth()
|
||||
static async me() {
|
||||
const ctx = getContext();
|
||||
const id = ctx.get("auth")!.sub;
|
||||
|
||||
const user = User.users.find((user) => user.id === id);
|
||||
|
||||
if (!user) {
|
||||
throw new ServiceError("User not found", {
|
||||
statusCode: 404,
|
||||
code: "USER_NOT_FOUND",
|
||||
});
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
@requireAuth()
|
||||
static async create() {
|
||||
const ctx = getContext();
|
||||
|
||||
const auth = ctx.get("auth")!;
|
||||
|
||||
// Check if the user already exists
|
||||
|
||||
if (User.users.find((user) => user.id === auth.sub)) {
|
||||
throw new ServiceError("User already exists", {
|
||||
statusCode: 400,
|
||||
code: "USER_ALREADY_EXISTS",
|
||||
});
|
||||
}
|
||||
|
||||
const user = new User(auth.sub, auth.username || "unknown", [
|
||||
"Welcome to Pylon with ZITADEL!",
|
||||
]);
|
||||
|
||||
User.users.push(user);
|
||||
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
export const graphql = {
|
||||
Query: {
|
||||
me: User.me,
|
||||
info: () => "Public Data",
|
||||
},
|
||||
Mutation: {
|
||||
createUser: User.create,
|
||||
},
|
||||
};
|
||||
|
||||
// Initialize the authentication middleware
|
||||
app.use("*", auth.initialize());
|
||||
|
||||
// Automatically try to create a user for each request for demonstration purposes
|
||||
app.use(async (_, next) => {
|
||||
try {
|
||||
await User.create();
|
||||
} catch {
|
||||
// Ignore errors
|
||||
// Fail silently if the user already exists
|
||||
}
|
||||
|
||||
await next();
|
||||
});
|
||||
|
||||
app.get("/img/api/info", (c) => {
|
||||
return new Response("Public Data");
|
||||
});
|
||||
|
||||
// The `auth.require()` middleware is optional here, as the `User.me` method already checks for it.
|
||||
app.get("/img/api/me", auth.require(), async (c) => {
|
||||
const user = await User.me();
|
||||
|
||||
return c.json(user);
|
||||
});
|
||||
|
||||
// A role check for `read:messages` is not required here, as the `user.messages` method already checks for it.
|
||||
app.get("/img/api/me/messages", auth.require(), async (c) => {
|
||||
const user = await User.me();
|
||||
|
||||
// This will throw an error if the user does not have the `read:messages` role
|
||||
return c.json(await user.messages());
|
||||
});
|
||||
|
||||
export default app;
|
||||
```
|
||||
|
||||
### Call the API
|
||||
|
||||
To call the API you need an access token, which is then verified by ZITADEL.
|
||||
Please follow [this guide here](/guides/integrate/token-introspection/private-key-jwt), ignoring the first step as we already have the `.json`-key-file from the serviceaccount.
|
||||
|
||||
<Callout>
|
||||
You can also create a PAT for the serviceuser and use it to test the API. For this, follow [this guide](/guides/integrate/service-users/personal-access-token#create-a-service-user-with-a-pat).
|
||||
</Callout>
|
||||
|
||||
Optionally set the token as an environment variable:
|
||||
|
||||
```
|
||||
export TOKEN='MtjHodGy4zxKylDOhg6kW90WeEQs2q...'
|
||||
```
|
||||
|
||||
Now you have to start the Pylon service:
|
||||
|
||||
```bash
|
||||
bun run dev
|
||||
```
|
||||
|
||||
With the access token, you can then do the following calls:
|
||||
|
||||
1. GraphQL:
|
||||
|
||||
```
|
||||
curl -H "Authorization: Bearer $TOKEN" -G http://localhost:3000/graphql --data-urlencode 'query={ info }'
|
||||
curl -H "Authorization: Bearer $TOKEN" -G http://localhost:3000/graphql --data-urlencode 'query={ me { id name } }'
|
||||
curl -H "Authorization: Bearer $TOKEN" -G http://localhost:3000/graphql --data-urlencode 'query={ me { id name messages } }'
|
||||
|
||||
```
|
||||
|
||||
You can also visit the GraphQL playground at `http://localhost:3000/graphql` and execute the queries there.
|
||||
|
||||
2. Routes:
|
||||
|
||||
```
|
||||
curl -H "Authorization: Bearer $TOKEN" -X GET http://localhost:3000/api/info
|
||||
curl -H "Authorization: Bearer $TOKEN" -X GET http://localhost:3000/api/me
|
||||
curl -H "Authorization: Bearer $TOKEN" -X GET http://localhost:3000/api/me/messages
|
||||
```
|
||||
|
||||
## Completion
|
||||
|
||||
Congratulations! You have successfully integrated your Pylon with ZITADEL!
|
||||
|
||||
If you get stuck, consider checking out their [documentation](https://pylon.cronit.io). If you face issues, contact Pylon or raise an issue on [GitHub](https://github.com/getcronit/pylon/issues).
|
||||
@@ -0,0 +1,165 @@
|
||||
---
|
||||
title: ZITADEL with Django Python
|
||||
sidebar_label: Django
|
||||
---
|
||||
|
||||
import AppJWT from '../imports/_app_jwt.mdx';
|
||||
import ServiceuserJWT from '../imports/_serviceuser_jwt.mdx';
|
||||
import ServiceuserRole from '../imports/_serviceuser_role.mdx';
|
||||
import SetupPython from '../imports/_setup_python.mdx';
|
||||
|
||||
This integration guide demonstrates the recommended way to incorporate ZITADEL into your Django Python application.
|
||||
It explains how to check the token validity in the API and how to check for permissions.
|
||||
|
||||
By the end of this guide, your application will have three different endpoint which are public, private(valid token) and private-scoped(valid token with specific role).
|
||||
|
||||
<Callout>
|
||||
This documentation references our [example](https://github.com/zitadel/example-django-python-oauth) on GitHub.
|
||||
</Callout>
|
||||
|
||||
## ZITADEL setup
|
||||
|
||||
Before we can start building our application, we have to do a few configuration steps in ZITADEL Management Console.
|
||||
|
||||
### Create application
|
||||
|
||||
<AppJWT components={props.components} />
|
||||
|
||||
### Create Serviceuser
|
||||
|
||||
<ServiceuserJWT components={props.components} />
|
||||
|
||||
### Give Serviceuser an authorization
|
||||
|
||||
<ServiceuserRole components={props.components} />
|
||||
|
||||
### Prerequisites
|
||||
|
||||
At the end you should have the following for the API:
|
||||
- Issuer, something like `https://example.zitadel.cloud` or `http://localhost:8080`
|
||||
- Introspection URL, something like `https://example.zitadel.cloud/oauth/v2/introspect`
|
||||
- Token URL, something like `https://example.zitadel.cloud/oauth/v2/token`
|
||||
- `.json`-key-file for the API, from the application
|
||||
- ID of the project
|
||||
|
||||
And the following from the Serviceuser:
|
||||
- `.json`-key-file from the serviceuser
|
||||
|
||||
## Setup new Django application
|
||||
|
||||
### Setup Python
|
||||
|
||||
<SetupPython components={props.components} />
|
||||
|
||||
### Install dependencies
|
||||
|
||||
For this example we need the following dependencies:
|
||||
- `django`: to create an API with django
|
||||
- `python-dotenv`: to use environment variables in the configuration
|
||||
- `authlib`: client-side OAuth functionality
|
||||
- `requests`: HTTP requests for the introspection
|
||||
|
||||
For the dependencies we need a requirements.txt-file with the following content:
|
||||
|
||||
```python reference
|
||||
https://github.com/zitadel/example-python-django-oauth/blob/main/requirements.txt
|
||||
```
|
||||
|
||||
Then install all dependencies with:
|
||||
```bash
|
||||
python -m pip install -U requirements.txt
|
||||
```
|
||||
|
||||
Then in your folder of choice, call the following command to create a Django base:
|
||||
```bash
|
||||
django-admin startproject myapi .
|
||||
```
|
||||
|
||||
## Define the Django API
|
||||
|
||||
### Add to the settings.py to include ZITADEL info
|
||||
|
||||
There is info needed for the introspection calls, which we put into the settings.py:
|
||||
|
||||
```python reference
|
||||
https://github.com/zitadel/example-python-django-oauth/blob/main/myapi/settings.py#L125-L133
|
||||
```
|
||||
|
||||
and create a ".env"-file in the root folder with the configuration as an example:
|
||||
```bash
|
||||
ZITADEL_INTROSPECTION_URL = 'URL to the introspection endpoint to verify the provided token'
|
||||
ZITADEL_DOMAIN = 'Domain used as audience in the token verification'
|
||||
API_PRIVATE_KEY_FILE_PATH = 'Path to the key.json created in ZITADEL'
|
||||
```
|
||||
|
||||
I should look something like this:
|
||||
|
||||
```bash
|
||||
ZITADEL_INTROSPECTION_URL = 'https://example.zitadel.cloud/oauth/v2/introspect'
|
||||
ZITADEL_DOMAIN = 'https://example.zitadel.cloud'
|
||||
API_PRIVATE_KEY_FILE_PATH = '/tmp/example/250719519163548112.json'
|
||||
```
|
||||
|
||||
### Validator definition
|
||||
|
||||
To validate the tokens, we need a validator which can be called in the event of API-calls.
|
||||
|
||||
validator.py:
|
||||
|
||||
```python reference
|
||||
https://github.com/zitadel/example-python-django-oauth/blob/main/myapi/validator.py
|
||||
```
|
||||
|
||||
### Requests and URLs
|
||||
|
||||
We define 3 different endpoints which differ in terms of requirements.
|
||||
views.py:
|
||||
|
||||
```python reference
|
||||
https://github.com/zitadel/example-python-django-oauth/blob/main/myapi/views.py
|
||||
```
|
||||
|
||||
To handle endpoints the urls have to be added to the urls.py:
|
||||
|
||||
```python reference
|
||||
https://github.com/zitadel/example-python-django-oauth/blob/main/myapi/urls.py
|
||||
```
|
||||
|
||||
### DB
|
||||
|
||||
Create and run migrations:
|
||||
|
||||
```bash
|
||||
python manage.py migrate
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
You can use a local Django server to test the application.
|
||||
|
||||
```bash
|
||||
python manage.py runserver
|
||||
```
|
||||
|
||||
### Call the API
|
||||
|
||||
To call the API you need an access token, which is then verified by ZITADEL.
|
||||
Please follow [this guide here](/guides/integrate/token-introspection/private-key-jwt), ignoring the first step as we already have the `.json`-key-file from the serviceaccount.
|
||||
|
||||
Optionally set the token as an environment variable:
|
||||
```
|
||||
export TOKEN='MtjHodGy4zxKylDOhg6kW90WeEQs2q...'
|
||||
```
|
||||
|
||||
With the access token, you can then do the following calls:
|
||||
```
|
||||
curl -H "Authorization: Bearer $TOKEN" -X GET http://localhost:8000/api/public
|
||||
curl -H "Authorization: Bearer $TOKEN" -X GET http://localhost:8000/api/private
|
||||
curl -H "Authorization: Bearer $TOKEN" -X GET http://localhost:8000/api/private-scoped
|
||||
```
|
||||
|
||||
## Completion
|
||||
|
||||
Congratulations! You have successfully integrated your Django API with ZITADEL!
|
||||
|
||||
If you get stuck, consider checking out our [example](https://github.com/zitadel/example-python-django-oauth) application. This application includes all the functionalities mentioned in this quick-start. You can start by cloning the repository and defining the settings in the settings.py. If you face issues, contact us or raise an issue on [GitHub](https://github.com/zitadel/example-python-django-oauth/issues).
|
||||
@@ -0,0 +1,255 @@
|
||||
---
|
||||
title: ZITADEL with Python
|
||||
sidebar_label: Python
|
||||
---
|
||||
|
||||
This example shows you how to secure a Python3 Flask API with both authentication and authorization using ZITADEL.
|
||||
|
||||
## Overview
|
||||
|
||||

|
||||
|
||||
The Python API will have public, private, and private-scoped routes and check if a user is authenticated and authorized to access the routes.
|
||||
The private routes expect an authorization header with a valid access token in the request. The access token is used as a bearer token to authenticate the user when calling the API.
|
||||
The API will validate the access token on the [introspect endpoint](/apis/openidoauth/endpoints#introspection-endpoint) and will receive the user's roles from ZITADEL.
|
||||
|
||||
The API application uses [Client Secret Basic](/apis/openidoauth/authn-methods#client-secret-basic) to authenticate against ZITADEL and access the introspection endpoint.
|
||||
You can use any valid access_token from a user or service account to send requests to the example API.
|
||||
In this example we will use a service account with a [personal access token](/guides/integrate/service-users/personal-access-token) which can be used directly to access the example API.
|
||||
|
||||
## Running the example
|
||||
|
||||
### Python Prerequisites
|
||||
|
||||
In order to run the example you need to have `python3` and `pip3` installed.
|
||||
|
||||
### ZITADEL configuration for the API
|
||||
|
||||

|
||||
|
||||
You need to setup a couple of things in ZITADEL.
|
||||
|
||||
1. If you don't have an instance yet, please go ahead and create an instance as explained [here](/guides/start/quickstart#3-create-your-zitadel-instance). Also, create a new project by following the steps [here](/guides/start/quickstart#4-create-your-project-and-application).
|
||||
|
||||
2. You must create an API application in your project. Follow [this guide](/guides/manage/console/applications-overview) to create a new application of type "API" with authentication method "Basic". Save both the ClientID and ClientSecret after you create the application.
|
||||
|
||||
### Create the API
|
||||
|
||||
1. Clone or download this [Python project](https://github.com/zitadel/example-api-python3-flask) to your workspace.
|
||||
|
||||
```
|
||||
git clone https://github.com/zitadel/example-api-python3-flask
|
||||
|
||||
cd example-api-python3-flask
|
||||
```
|
||||
2. The [server.py](https://github.com/zitadel/example-api-python3-flask/blob/main/server.py) file contains a Flask-based API that provides authentication for routes using the OpenID Connect protocol as shown below.
|
||||
|
||||
```python
|
||||
from flask import Flask, jsonify, Response
|
||||
from authlib.integrations.flask_oauth2 import ResourceProtector
|
||||
from validator import ZitadelIntrospectTokenValidator, ValidatorError
|
||||
|
||||
require_auth = ResourceProtector()
|
||||
require_auth.register_token_validator(ZitadelIntrospectTokenValidator())
|
||||
|
||||
APP = Flask(__name__)
|
||||
|
||||
@APP.errorhandler(ValidatorError)
|
||||
def handle_auth_error(ex: ValidatorError) -> Response:
|
||||
|
||||
response = jsonify(ex.error)
|
||||
response.status_code = ex.status_code
|
||||
return response
|
||||
|
||||
@APP.route("/img/api/public")
|
||||
def public():
|
||||
"""No access token required."""
|
||||
response = (
|
||||
"Public route - You don't need to be authenticated to see this."
|
||||
)
|
||||
return jsonify(message=response)
|
||||
|
||||
@APP.route("/img/api/private")
|
||||
@require_auth(None)
|
||||
def private():
|
||||
"""A valid access token is required."""
|
||||
response = (
|
||||
"Private route - You need to be authenticated to see this."
|
||||
)
|
||||
return jsonify(message=response)
|
||||
|
||||
@APP.route("/img/api/private-scoped")
|
||||
@require_auth(["read:messages"])
|
||||
def private_scoped():
|
||||
"""A valid access token and scope are required."""
|
||||
response = (
|
||||
"Private, scoped route - You need to be authenticated and have the role read:messages to see this."
|
||||
)
|
||||
return jsonify(message=response)
|
||||
|
||||
if __name__ == "__main__":
|
||||
APP.run()
|
||||
```
|
||||
|
||||
The API has three routes:
|
||||
|
||||
<ul>
|
||||
<li> "/img/api/public" - No access token is required.</li>
|
||||
<li>"/img/api/private" - A valid access token is required.</li>
|
||||
<li>"/img/api/private-scoped" - A valid access token and a "read:messages" scope are required.</li>
|
||||
</ul>
|
||||
|
||||
The [validator.py](https://github.com/zitadel/example-api-python3-flask/blob/main/validator.py) file implements the ZitadelIntrospectTokenValidator class, which is a custom class that inherits from the IntrospectTokenValidator class provided by the authlib library. The introspection process retrieves the token details from ZITADEL using ZITADEL's introspection endpoint.
|
||||
|
||||
```python
|
||||
from os import environ as env
|
||||
import os
|
||||
import time
|
||||
from typing import Dict
|
||||
|
||||
from authlib.oauth2.rfc7662 import IntrospectTokenValidator
|
||||
import requests
|
||||
from dotenv import load_dotenv, find_dotenv
|
||||
from requests.auth import HTTPBasicAuth
|
||||
|
||||
load_dotenv()
|
||||
|
||||
ZITADEL_DOMAIN = os.getenv("ZITADEL_DOMAIN")
|
||||
CLIENT_ID = os.getenv("CLIENT_ID")
|
||||
CLIENT_SECRET = os.getenv("CLIENT_SECRET")
|
||||
|
||||
class ValidatorError(Exception):
|
||||
|
||||
def __init__(self, error: Dict[str, str], status_code: int):
|
||||
super().__init__()
|
||||
self.error = error
|
||||
self.status_code = status_code
|
||||
|
||||
# Use Introspection in Resource Server
|
||||
# https://docs.authlib.org/en/latest/specs/rfc7662.html#require-oauth-introspection
|
||||
|
||||
class ZitadelIntrospectTokenValidator(IntrospectTokenValidator):
|
||||
def introspect_token(self, token_string):
|
||||
url = f'{ZITADEL_DOMAIN}/oauth/v2/introspect'
|
||||
data = {'token': token_string, 'token_type_hint': 'access_token', 'scope': 'openid'}
|
||||
auth = HTTPBasicAuth(CLIENT_ID, CLIENT_SECRET)
|
||||
resp = requests.post(url, data=data, auth=auth)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
def match_token_scopes(self, token, or_scopes):
|
||||
if or_scopes is None:
|
||||
return True
|
||||
roles = token["urn:zitadel:iam:org:project:roles"].keys()
|
||||
for and_scopes in or_scopes:
|
||||
scopes = and_scopes.split()
|
||||
"""print(f"Check if all {scopes} are in {roles}")"""
|
||||
if all(key in roles for key in scopes):
|
||||
return True
|
||||
return False
|
||||
|
||||
def validate_token(self, token, scopes, request):
|
||||
print (f"Token: {token}\n")
|
||||
now = int( time.time() )
|
||||
if not token:
|
||||
raise ValidatorError({
|
||||
"code": "invalid_token_revoked",
|
||||
"description": "Token was revoked." }, 401)
|
||||
"""Expired"""
|
||||
if token["exp"] < now:
|
||||
raise ValidatorError({
|
||||
"code": "invalid_token_expired",
|
||||
"description": "Token has expired." }, 401)
|
||||
"""Revoked"""
|
||||
if not token["active"]:
|
||||
raise InvalidTokenError()
|
||||
"""Insufficient Scope"""
|
||||
if not self.match_token_scopes(token, scopes):
|
||||
raise ValidatorError({
|
||||
"code": "insufficient_scope",
|
||||
"description": f"Token has insufficient scope. Route requires: {scopes}" }, 401)
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
res = self.introspect_token(*args, **kwargs)
|
||||
return res
|
||||
```
|
||||
|
||||
3. Create a new file named ".env" in the directory. Copy the configuration in the [".env.example"](https://github.com/zitadel/example-api-python3-flask/blob/main/.env.example) file to the newly created .env file. Set the values with your Custom Domain/Issuer URL, Client ID, and Client Secret from the previous steps. Obtain your Issuer URL by following [these steps](/guides/start/quickstart#5-collect-your-integration-keys).
|
||||
|
||||
```python
|
||||
ZITADEL_DOMAIN = "https://custom-domain-abcdef.zitadel.cloud"
|
||||
CLIENT_ID = "197....@projectname"
|
||||
CLIENT_SECRET = "NVAp70IqiGmJldbS...."
|
||||
```
|
||||
|
||||
### ZITADEL configuration to create a service user
|
||||
|
||||

|
||||
|
||||
1. Create a service user and a Personal Access Token (PAT) for that user by following [this guide](/guides/integrate/service-users/personal-access-token#create-a-service-user-with-a-pat).
|
||||
2. To enable authorization, follow [this guide](/guides/manage/console/roles) to create a role `read:messages` on your project.
|
||||
3. Next, create an authorization for the service user you created by adding the role `read:messages` to the user. Follow this [guide](/guides/manage/console/roles#authorizations) for more information on creating an authorization.
|
||||
|
||||
### Run the API
|
||||
|
||||
1. Install required dependencies by running `pip3 install -r requirements.txt` on your terminal.
|
||||
2. Run the API with the `python3 server.py` command.
|
||||
3. Open another terminal and follow the next step to test the API.
|
||||
|
||||
## Test the API
|
||||
|
||||
### Public route
|
||||
|
||||
Invoke the public route by running the following command:
|
||||
|
||||
```
|
||||
curl --request GET \
|
||||
--url http://127.0.0.1:5000/api/public
|
||||
```
|
||||
|
||||
You should get a response with Status Code 200 and the following message.
|
||||
|
||||
`{"message":"Public route - You don't need to be authenticated to see this."}`
|
||||
|
||||
### Private route
|
||||
|
||||
Call the private route without authorization headers by running the following command:
|
||||
|
||||
```
|
||||
curl --request GET \
|
||||
--url http://127.0.0.1:5000/api/private
|
||||
```
|
||||
|
||||
You should get a response with Status Code 401 and an error message.
|
||||
|
||||
Now let's add an authorization header to your request. Save the personal access token for your service user to a variable by running the following command. Replace the value with the PAT you obtained earlier.
|
||||
|
||||
`PAT=nr9vnUTkQkn4rxWk...`
|
||||
|
||||
Then call the private route with the PAT in the authorization header.
|
||||
|
||||
```
|
||||
curl --request GET \
|
||||
--url http://127.0.0.1:5000/api/private \
|
||||
--header "authorization: Bearer $PAT"
|
||||
```
|
||||
|
||||
Now you should get a response with Status Code 200 and the following message.
|
||||
|
||||
`{"message":"Private route - You need to be authenticated to see this."}`
|
||||
|
||||
### Private route, protected
|
||||
|
||||
Call the private route that requires the user to have a certain role
|
||||
|
||||
```
|
||||
curl --request GET \
|
||||
--url http://127.0.0.1:5000/api/private-scoped \
|
||||
--header "authorization: Bearer $PAT"
|
||||
```
|
||||
|
||||
You should get a response with Status Code 200 and the following message.
|
||||
|
||||
`{"message":"Private, scoped route - You need to be authenticated and have the role read:messages to see this."}`
|
||||
|
||||
You can remove the role from the service user in ZITADEL and try again. You should then get a Status Code 403, Forbidden error.
|
||||
Reference in New Issue
Block a user