mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-21 06:54:25 +00:00
docs: improve documentation for v2 release (#4046)
* WIP: docs(proxy): describe proxy settings * fix nginx * refactor (docs): deploy and operate sections * chore: ignore package-lock since we use yarn * chore: update to rc1 * chore: broken links * chore: update yarn * docs: move disclaimer to bottom * chore: fix broken links * Update docs/docs/guides/operate/tls_modes.mdx Co-authored-by: Fabi <[email protected]> * test caddy files * syntax highlight * traefik example * refactor: docs * refactor * working state * got a working state * remove bar * mark rate limits for update * remove zitadel.ch * fix cases * docs: zitadel quickstart * docs: zitadel quickstart * docs: create app and project * docs: move customer portal docs to guides manage cloud * docs: move customer portal docs to guides manage cloud * docs: move customer portal docs to guides manage cloud * docs: add help me choose in the quickstart * docs: broken links * fix broken links * Update knative guide * styling * docs: support customer portal * update to main instead v2-alpha * use version 2 tag * docs: images * docs: move authentication and authorization guides to integrate * docs: quickstart use examples * docs: lb example * fix broken link * docs: update userinfo endpoints * docs: update userinfo endpoints * fix oidc endpoint * docs: remove unused endpoints in app.module Co-authored-by: Fabi <[email protected]> Co-authored-by: Fabienne <[email protected]> Co-authored-by: Livio Amstutz <[email protected]>
This commit is contained in:
co-authored by
Fabi
Fabienne
Livio Amstutz
parent
fb52575f79
commit
3c3bce1a6b
@@ -0,0 +1,118 @@
|
||||
---
|
||||
title: .NET
|
||||
---
|
||||
|
||||
This integration guide shows you how to integrate **ZITADEL** into your .NET application.
|
||||
It demonstrates how to fetch some data from the ZITADEL management API.
|
||||
|
||||
At the end of the guide you should have an application able to read the details of your organization.
|
||||
|
||||
If you need any other information about the .NET SDK go to the [documentation](https://caos.github.io/zitadel-net/) of the SDK itself.
|
||||
## Prerequisites
|
||||
|
||||
The client [SDK](https://github.com/zitadel/zitadel-net) will handle all necessary OAuth 2.0 requests and send the required headers to the ZITADEL API.
|
||||
All that is required, is a service account with an Org Owner (or another role, depending on the needed api requests) role assigned and its key JSON.
|
||||
|
||||
However, we recommend you read the guide on [how to access ZITADEL API](../../guides/integrate/access-zitadel-apis) and the associated guides for a basic knowledge of :
|
||||
- [Recommended Authorization Flows](../../guides/integrate/oauth-recommended-flows.md)
|
||||
- [Service Users](../../guides/integrate/serviceusers.md)
|
||||
|
||||
> Be sure to have a valid key JSON and that its service account is either ORG_OWNER or at least ORG_OWNER_VIEWER before you continue with this guide.
|
||||
|
||||
## .NET Setup
|
||||
|
||||
### Create a .NET application
|
||||
|
||||
Use the IDE of your choice or the command line to create a new application.
|
||||
|
||||
```bash
|
||||
dotnet new web
|
||||
```
|
||||
|
||||
### Install the package
|
||||
|
||||
Install the package via nuget
|
||||
|
||||
```bash
|
||||
dotnet add package Zitadel.Api
|
||||
```
|
||||
|
||||
### Create example client
|
||||
|
||||
Change the program.cs file to the content below. This will create a client for the management api and call its `GetMyUsers` function.
|
||||
The SDK will make sure you will have access to the API by retrieving a Bearer Token using JWT Profile with the provided scopes (`openid` and `urn:zitadel:iam:org:project:id:{projectID}:aud`).
|
||||
|
||||
Make sure to fill the const `apiUrl`, `apiProject` and `personalAccessToken` with your own instance data. The used vars below are from a test instance, to show you how it should look.
|
||||
The apiURL is the domain of your instance you can find it on the instance detail in the Customer Portal or in the Console
|
||||
The apiProject you will find in the ZITADEL project in the first organization of your instance.
|
||||
|
||||
```csharp
|
||||
// This file contains two examples:
|
||||
// 1. An example with a service account "personal access token" to access the ZITADEL API.
|
||||
// 2. An example with a service account "jwt profile key" to access the ZITADEL API.
|
||||
|
||||
using Zitadel.Api;
|
||||
using Zitadel.Credentials;
|
||||
|
||||
const string apiUrl = "https://zitadel-libraries-l8boqa.zitadel.cloud";
|
||||
const string personalAccessToken = "ge85fvmgTX4XAhjpF0XGpelB2vn9LZanJaqmUQDuf7iTpKVowb44LFl-86pqY2mfJCEoIOk";
|
||||
|
||||
// or create the token provider directly:
|
||||
// new StaticTokenProvider(token)
|
||||
var client = Clients.AuthService(new(apiUrl, ITokenProvider.Static(personalAccessToken)));
|
||||
var result = await client.GetMyUserAsync(new());
|
||||
Console.WriteLine($"User: {result.User}");
|
||||
|
||||
const string apiProject = "170078979166961921";
|
||||
var serviceAccount = ServiceAccount.LoadFromJsonString(
|
||||
@"
|
||||
{
|
||||
""type"": ""serviceaccount"",
|
||||
""keyId"": ""170084658355110145"",
|
||||
""key"": ""-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAnQisbU4FuLmjLR9I2Q01Rm9Mx6WySat2mbxgmOzu04oXuESI\nyS+RkiimdN0khjqouBftYqtVes7yngMLq3E8hMCwv/kLE+YeXphZXnn8tps8M2gV\n7S//uCp9LooK9qeh0lSkOqIsh0atj/l7NAHFxnhuNhfmn8XIYJNLVNSj5yzTri5E\nSn92SAsUQLSONgr7IEmIjcuPtYeU0iLvVno52ljZHnPX2WJ0HEZv44nZpkR4qBfv\n3hJzNx7sd4TdPGHHugJD8jdG/X4bAxwL5XGHZu18cUVM5RerSMpFQHSuIGgpKmK4\nWlM1AJGeut6EX/SrCxUDvhyOnXAgqhunTUmi6QIDAQABAoIBAHn7y92Y1y743X3m\nqHMbJIBTYyRPXaCGljm0MKF6o8clpWlZq5wE3KLZ+vwa8Q1oMbnXtGqKR3t/mM4P\n9Ze2/djtyh9GOUm632qCFCIkxp+fFPOl7ipyt8V7FAT77KpP6490eqKlacunppmJ\nph/vJJAY6xwQEvGX9SC4KrN5/txLKXbVtR3V2RXy9sxbbL4cpnklmRBMeXQkpwEM\nTKELUr5Rmhg9KvS3yALgVv0dIRtOA8Z995R234hXfY0St48YEvZtsxeme47u2CVl\nHJcVH4aa9Sw6XlgAEQBxqbQHpcLvUIu3XempO7VfGklWE6OlGuEcnUWpJCD8jMZW\nPYtt9LUCgYEAwi8josS3Iyto+DMJjJKCw175N2cmFMxBGu9Rw4aHjTiN57z7AUkn\nbmT44WnSmc1bCLC+nMB34vhiEyBKXYrH7zgbeMO8QDG3aO6gXdod/IdsieZR8E3b\ngUA1wtZYyRbc7eo8U4Nqkv1NXVRuDJkz/Mfoy+m1BVKcW7YeZaaZN9MCgYEAzwYB\n/LAiJoyx5UPwuieizlT7kHI7uvZRo4oLx+cZipNCJ0NGKgX4l1NIYLaNDbCoT9N0\nylico+kn+nihzDmD6SjY2hHGSIHk7AnJOcW+Bk5TfsYb8clxfgX40udLMIS0F13R\nrJt0gD9x0O3AZv4MV9cSI0/Md0tbWePgrLI44NMCgYEAojj7TlmEnY8AbIlGqvci\n4tCO5qf3elyA712LMwtKZsIeWsDX+OUCWglkmfvsAq06JfJx60YnYagbVtsdBTSR\nftmiqarrs71U+gaQVpeHgZYpKLMPNO/2Nu5Le2/SUHwXKXML3sDk4dNXNGb6YPAE\nLGNdqiyeG8o98agdkNIzIh0CgYEAlTGhMPfGRL3UXoNN8vopjEUWXozUmvJ090S/\nJLtZXtKtNBp5cEOJWZT9biVhFeKgCZc8ba7ahA29b/aLs+AnPlrfnJh+qzZhQfHz\ngJ0PSwAbkBs5fFBOaCHppiRlvXuFRemo95m4pcwTPBx7Mj4Xqx4lxij2E2rNVMSy\n4AI4l10CgYBwefqXt8B+D+0EvmhyHk19Tk8/fPelclJUv/IVI59c0F9UMAA2rD1U\nNW6k9251OGU7mQkztluNvl13qtAW/DveOjkFeDJIMzhFjravpLQXhUK4ETnM44YL\nFbClVGJaHYSHgOkNpcN5lYVLoyEvzv9rEPwBqpZRVnwWj6L+/I2L5Q==\n-----END RSA PRIVATE KEY-----\n"",
|
||||
""userId"": ""170079991923474689""
|
||||
}");
|
||||
client = Clients.AuthService(
|
||||
new(
|
||||
apiUrl,
|
||||
ITokenProvider.ServiceAccount(
|
||||
serviceAccount,
|
||||
apiUrl,
|
||||
apiProject)));
|
||||
result = await client.GetMyUserAsync(new());
|
||||
Console.WriteLine($"User: {result.User}");
|
||||
```
|
||||
|
||||
### Test client
|
||||
|
||||
After you have configured everything correctly, you can simply start the example by:
|
||||
|
||||
```bash
|
||||
dotnet run
|
||||
```
|
||||
|
||||
This will output something similar to:
|
||||
|
||||
```
|
||||
User: {"FirstName": "MyName", "LastName": "MyLastName" ... }
|
||||
```
|
||||
|
||||
## Completion
|
||||
|
||||
You have successfully used the ZITADEL .NET SDK to call the auth API!
|
||||
To use the auth API you will not need a specific role, because only an authenticated user is needed.
|
||||
|
||||
For accessing the admin or management API the user will need some specific roles.
|
||||
If you encountered an error (e.g. `code = PermissionDenied desc = No matching permissions found`),
|
||||
ensure your service user has the required permissions by assigning the `ORG_OWNER` or `ORG_OWNER_VIEWER` role
|
||||
and check the mentioned [guides](#prerequisites) at the beginning.
|
||||
|
||||
If you've run into any other problem, don't hesitate to contact us or raise an issue on [ZITADEL](https://github.com/zitadel/zitadel/issues) or in the [SDK](https://github.com/zitadel/zitadel-go/issues).
|
||||
|
||||
### Whats next?
|
||||
|
||||
Now you can proceed implementing our APIs by adding more calls.
|
||||
|
||||
Checkout more [examples from the SDK](https://github.com/zitadel/zitadel-go/blob/main/example) or refer to our [API Docs](../../apis/introduction).
|
||||
|
||||
> This guide will be updated soon to show you how to use the SDK for your own API as well.
|
||||
@@ -0,0 +1,153 @@
|
||||
---
|
||||
title: Go
|
||||
---
|
||||
|
||||
This integration guide shows you how to integrate **ZITADEL** into your Go application.
|
||||
It demonstrates how to fetch some data from the ZITADEL management API.
|
||||
|
||||
At the end of the guide you should have an application able to read the details of your organization.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
The client [SDK](https://github.com/zitadel/zitadel-go) will handle all necessary OAuth 2.0 requests and send the required headers to the ZITADEL API using our [OIDC client library](https://github.com/zitadel/oidc).
|
||||
All that is required, is a service account with an Org Owner (or another role, depending on the needed api requests) role assigned and its key JSON.
|
||||
|
||||
However, we recommend you read the guide on [how to access ZITADEL API](../../guides/integrate/access-zitadel-apis) and the associated guides for a basic knowledge of :
|
||||
- [Recommended Authorization Flows](../../guides/integrate/oauth-recommended-flows.md)
|
||||
- [Service Users](../../guides/integrate/serviceusers.md)
|
||||
|
||||
> Be sure to have a valid key JSON and that its service account is either ORG_OWNER or at least ORG_OWNER_VIEWER before you continue with this guide.
|
||||
|
||||
## Go Setup
|
||||
|
||||
### Add Go SDK to your project
|
||||
|
||||
You need to add the SDK into Go Modules by:
|
||||
|
||||
```bash
|
||||
go get github.com/zitadel/zitadel-go/v2
|
||||
```
|
||||
|
||||
### Create example client
|
||||
|
||||
Create a new go file with the content below. This will create a client for the management api and call its `GetMyOrg` function.
|
||||
The SDK will make sure you will have access to the API by retrieving a Bearer Token using JWT Profile with the provided scopes (`openid` and `urn:zitadel:iam:org:project:id:{projectID}:aud`).
|
||||
Make sure to fill the vars `issuer`, `api`, `projectID `and `orgID`
|
||||
|
||||
The issuer and api is the domain of your instance you can find it on the instance detail in the ZITADEL Cloud Customer Portal or in the ZITADEL Console.
|
||||
The projectID you will find in the ZITADEL project in the first organization of your instance and the orgID on the first organization.
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"log"
|
||||
|
||||
"github.com/zitadel/oidc/pkg/oidc"
|
||||
|
||||
"github.com/zitadel/zitadel-go/v2/pkg/client/management"
|
||||
"github.com/zitadel/zitadel-go/v2/pkg/client/middleware"
|
||||
"github.com/zitadel/zitadel-go/v2/pkg/client/zitadel"
|
||||
pb "github.com/zitadel/zitadel-go/v2/pkg/client/zitadel/management"
|
||||
)
|
||||
|
||||
var (
|
||||
issuer = flag.String("issuer", "", "issuer of your ZITADEL instance (in the form: https://<instance>.zitadel.cloud or https://<yourdomain>)")
|
||||
api = flag.String("api", "", "gRPC endpoint of your ZITADEL instance (in the form: <instance>.zitadel.cloud:443 or <yourdomain>:443)")
|
||||
projectID = flag.String("projectID", "", "ZITADEL projectID in your instance")
|
||||
orgID = flag.String("orgID", "", "orgID to set for overwrite example")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
client, err := management.NewClient(
|
||||
*issuer,
|
||||
*api,
|
||||
[]string{oidc.ScopeOpenID, zitadel.ScopeProjectID(*projectID)},
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalln("could not create client", err)
|
||||
}
|
||||
defer func() {
|
||||
err := client.Connection.Close()
|
||||
if err != nil {
|
||||
log.Println("could not close grpc connection", err)
|
||||
}
|
||||
}()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
resp, err := client.GetMyOrg(ctx, &pb.GetMyOrgRequest{})
|
||||
if err != nil {
|
||||
log.Fatalln("call failed: ", err)
|
||||
}
|
||||
log.Printf("%s was created on: %s", resp.Org.Name, resp.Org.Details.CreationDate.AsTime())
|
||||
|
||||
respOverwrite, err := client.GetMyOrg(middleware.SetOrgID(ctx, *orgID), &pb.GetMyOrgRequest{})
|
||||
if err != nil {
|
||||
log.Fatalln("call failed: ", err)
|
||||
}
|
||||
log.Printf("%s was created on: %s", respOverwrite.Org.Name, respOverwrite.Org.Details.CreationDate.AsTime())
|
||||
```
|
||||
|
||||
#### Key JSON
|
||||
|
||||
To provide the key JSON to the SDK, simply set an environment variable `ZITADEL_KEY_PATH` with the path to the JSON as value.
|
||||
|
||||
```bash
|
||||
export ZITADEL_KEY_PATH=/Users/test/servicekey.json
|
||||
```
|
||||
|
||||
For development purposes you should be able to set this in your IDE.
|
||||
|
||||
If you're not able to set it via environment variable, you can also pass it with an additional option:
|
||||
|
||||
```go
|
||||
client, err := management.NewClient(
|
||||
[]string{oidc.ScopeOpenID, zitadel.ScopeZitadelAPI()},
|
||||
zitadel.WithKeyPath("/Users/test/servicekey.json"),
|
||||
)
|
||||
```
|
||||
|
||||
### Test client
|
||||
|
||||
After you have configured everything correctly, you can simply start the example by:
|
||||
|
||||
```bash
|
||||
go run main.go
|
||||
```
|
||||
|
||||
This will output something similar to:
|
||||
|
||||
```
|
||||
2021/04/21 11:27:36 DemoOrg was created on: 2021-04-08 13:36:05.578194 +0000 UTC
|
||||
```
|
||||
|
||||
## Completion
|
||||
|
||||
You have successfully used the ZITADEL Go SDK to call the management API!
|
||||
|
||||
If you encountered an error (e.g. `code = PermissionDenied desc = No matching permissions found`),
|
||||
ensure your service user has the required permissions by assigning the `ORG_OWNER` or `ORG_OWNER_VIEWER` role
|
||||
and check the mentioned [guides](#prerequisites) at the beginning.
|
||||
|
||||
If you've run into any other problem, don't hesitate to contact us or raise an issue on [ZITADEL](https://github.com/zitadel/zitadel/issues) or in the [SDK](https://github.com/zitadel/zitadel-go/issues).
|
||||
|
||||
### Whats next?
|
||||
|
||||
Now you can proceed implementing our APIs by adding more calls or trying to overwrite the organization context:
|
||||
|
||||
```go
|
||||
respOverwrite, err := client.GetMyOrg(middleware.SetOrgID(ctx, "74161146763996133"), &pb.GetMyOrgRequest{})
|
||||
if err != nil {
|
||||
log.Fatalln("call failed: ", err)
|
||||
}
|
||||
log.Printf("%s was created on: %s", respOverwrite.Org.Name, respOverwrite.Org.Details.CreationDate.AsTime())
|
||||
}
|
||||
```
|
||||
Checkout more [examples from the SDK](https://github.com/zitadel/zitadel-go/blob/main/example) or refer to our [API Docs](../../apis/introduction).
|
||||
|
||||
> This guide will be updated soon to show you how to use the SDK for your own API as well.
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
title: OAuth 2.0 Proxy
|
||||
---
|
||||
|
||||
<!-- //TODO Florian update this to zitadel.cloud-->
|
||||
|
||||
[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 loose 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://{your_domain}.zitadel.cloud"
|
||||
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 v6.1.1 (built with go1.14.2)`
|
||||
|
||||
## Completion
|
||||
|
||||
You have successfully integrated ZITADEL in your proxy!
|
||||
|
||||
### What next?
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
title: Overview
|
||||
---
|
||||
|
||||
import Tabs from '@theme/Tabs';
|
||||
import TabItem from '@theme/TabItem';
|
||||
import {Card, CardWrapper} from '../../src/components/card';
|
||||
|
||||
Get started with ZITADEL quickly by reading a quickstart or by cloning an example from our [ZITADEL examples](https://github.com/zitadel/zitadel-examples) repo.
|
||||
|
||||
<Tabs>
|
||||
<TabItem value="app" label="Web · Native applications" default>
|
||||
<CardWrapper>
|
||||
<Card link="/docs/examples/login/angular" imageSource="/img/tech/angular.svg" title="Angular" description="Add the user login to your application and query some data from the userinfo endpoint" />
|
||||
<Card link="/docs/examples/login/react" imageSource="/img/tech/react.png" title="React" description="Logs into your application and queries some data from the userinfo endpoint" />
|
||||
<Card link="/docs/examples/login/flutter" imageSource="/img/tech/flutter.svg" title="Flutter" description="Mobile Application working for iOS and Android that authenticates your user." />
|
||||
<Card link="/docs/examples/login/nextjs" imageSource="/img/tech/nextjs.svg" title="NextJS" description="A simple application to log into your user account and query some data from User endpoint." />
|
||||
</CardWrapper>
|
||||
</TabItem>
|
||||
<TabItem value="backend" label="Backend · API">
|
||||
<CardWrapper>
|
||||
<Card link="/docs/quickstarts/call-zitadel-api/go" imageSource="/img/tech/golang.svg" title="GO" description="Demonstrates how to fetch some data from the ZITADEL management API." />
|
||||
<Card link="/docs/quickstarts/call-zitadel-api/dot-net" imageSource="/img/tech/dotnet.svg" title=".NET" description="This integration guide shows you how to integrate ZITADEL into your .NET application. It demonstrates how to fetch some data from the ZITADEL management API." />
|
||||
</CardWrapper>
|
||||
</TabItem>
|
||||
<TabItem value="proxy" label="Proxy">
|
||||
<CardWrapper>
|
||||
<Card link="/docs/quickstarts/identity-proxy/oauth2-proxy" imageSource="/img/tech/oauth2-proxy.svg" title="OAuth 2.0 Proxy" description="Allows services to delegate the authentication flow to a IDP, for example ZITADEL" />
|
||||
</CardWrapper>
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
## Clone a sample project
|
||||
|
||||
<CardWrapper>
|
||||
<Card githubLink="https://github.com/zitadel/zitadel-examples/tree/main/java/spring-boot" title="Java" label="Java" />
|
||||
<Card githubLink="https://github.com/zitadel/zitadel-examples/tree/main/python3" title="Python" label="Python" />
|
||||
<Card githubLink="https://github.com/zitadel/zitadel-examples/tree/main/angular" title="Angular" label="Web · Mobile Web" />
|
||||
<Card githubLink="https://github.com/zitadel/zitadel-examples/tree/main/nextjs" title="NextJS" label="Web · Mobile Web" />
|
||||
</CardWrapper>
|
||||
|
||||
## Libraries
|
||||
|
||||
|
||||
| Language | Description | Link |
|
||||
| ------------ | ---------------------|-------------|
|
||||
| Go | Go client library for ZITADEL. | [https://github.com/zitadel/zitadel-go](https://github.com/zitadel/zitadel-go)
|
||||
| .Net | Authentication / Authorization library written in dotnet for the asp.net web application package. | [https://github.com/zitadel/zitadel-net](https://github.com/zitadel/zitadel-net)
|
||||
| Dart | Dart library for ZITADEL, contains gRPC and API access elements. | [https://github.com/zitadel/zitadel-dart](https://github.com/zitadel/zitadel-dart) |
|
||||
| Elixir | API Client for the ZITADEL API. | [https://github.com/jshmrtn/zitadel_api](https://github.com/jshmrtn/zitadel_api) |
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
title: Libraries
|
||||
---
|
||||
|
||||
|
||||
| Language | Description | Link |
|
||||
| ------------ | ---------------------|-------------|
|
||||
| Go | Go client library for ZITADEL. | [https://github.com/zitadel/zitadel-go](https://github.com/zitadel/zitadel-go)
|
||||
| .Net | Authentication / Authorization library written in dotnet for the asp.net web application package. | [https://github.com/zitadel/zitadel-net](https://github.com/zitadel/zitadel-net)
|
||||
| Dart | Dart library for ZITADEL, contains gRPC and API access elements. | [https://github.com/zitadel/zitadel-dart](https://github.com/zitadel/zitadel-dart) |
|
||||
| Elixir | API Client for the ZITADEL API. | [https://github.com/jshmrtn/zitadel_api](https://github.com/jshmrtn/zitadel_api) |
|
||||
|
||||
@@ -0,0 +1,324 @@
|
||||
---
|
||||
title: Angular
|
||||
---
|
||||
|
||||
This integration guide shows you the recommended way to integrate ZITADEL into your Angular application.
|
||||
It shows how to add user login to your application and fetch some data from the user info endpoint.
|
||||
|
||||
At the end of the guide, your application has login functionality and has access to the current user's profile.
|
||||
|
||||
> This documentation refers to our [example](https://github.com/zitadel/zitadel-examples/tree/main/angular) in GitHub. Note that we've written ZITADEL Console in Angular, so you can also use that as a reference.
|
||||
|
||||
## 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. 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 Web application type and continue.
|
||||
We recommend you use [Authorization Code](../../apis/openidoauth/grant-types#authorization-code) in combination with [Proof Key for Code Exchange (PKCE)](../../apis/openidoauth/grant-types#proof-key-for-code-exchange) for all web applications.
|
||||
|
||||

|
||||
|
||||
### 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-examples/tree/main/angular), set dev mode to `true` and the Redirect URIs to <http://localhost:4200/auth/callback>.
|
||||
|
||||
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 Angular client.
|
||||
|
||||
## Angular Setup
|
||||
|
||||
Now that you have your web application configured on the ZITADEL side, you can go ahead and integrate your Angular client.
|
||||
|
||||
### Install Angular Dependencies
|
||||
|
||||
You need to install an OAuth / OIDC client to connect with ZITADEL. Run the following command:
|
||||
|
||||
```bash
|
||||
npm install angular-oauth2-oidc
|
||||
```
|
||||
|
||||
### Create and Configure Auth Module
|
||||
|
||||
Add _OAuthModule_ to your Angular imports in _AppModule_ and provide the _AuthConfig_ in the providers' section. Also, ensure you import the _HTTPClientModule_.
|
||||
|
||||
```ts
|
||||
...
|
||||
import { AuthConfig, OAuthModule } from 'angular-oauth2-oidc';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
|
||||
const authConfig: AuthConfig = {
|
||||
scope: 'openid profile email',
|
||||
responseType: 'code',
|
||||
oidc: true,
|
||||
clientId: 'YOUR-CLIENT-ID', // replace with your appid
|
||||
issuer: 'https:/[your-domain]-[random-string].zitadel.cloud', // replace with your instance
|
||||
redirectUri: 'http://localhost:4200/auth/callback',
|
||||
postLogoutRedirectUri: 'http://localhost:4200/signedout', // optional
|
||||
requireHttps: false // required for running locally
|
||||
};
|
||||
|
||||
@NgModule({
|
||||
...
|
||||
imports: [
|
||||
OAuthModule.forRoot(),
|
||||
HttpClientModule,
|
||||
...
|
||||
providers: [
|
||||
{
|
||||
provide: AuthConfig,
|
||||
useValue: authConfig
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
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 successful login, ZITADEL redirects the user back to the redirect URI configured in _AuthModule_ and ZITADEL Console. Make sure both correspond, otherwise ZITADEL throws an error.
|
||||
|
||||
```ts
|
||||
import { Injectable } from "@angular/core";
|
||||
import { AuthConfig, OAuthService } from "angular-oauth2-oidc";
|
||||
import { BehaviorSubject, from, Observable } from "rxjs";
|
||||
|
||||
import { StatehandlerService } from "./statehandler.service";
|
||||
|
||||
@Injectable({
|
||||
providedIn: "root",
|
||||
})
|
||||
export class AuthenticationService {
|
||||
private _authenticated: boolean = false;
|
||||
private readonly _authenticationChanged: BehaviorSubject<boolean> =
|
||||
new BehaviorSubject(this.authenticated);
|
||||
|
||||
constructor(
|
||||
private oauthService: OAuthService,
|
||||
private authConfig: AuthConfig,
|
||||
private statehandler: StatehandlerService
|
||||
) {}
|
||||
|
||||
public get authenticated(): boolean {
|
||||
return this._authenticated;
|
||||
}
|
||||
|
||||
public get authenticationChanged(): Observable<boolean> {
|
||||
return this._authenticationChanged;
|
||||
}
|
||||
|
||||
public getOIDCUser(): Observable<any> {
|
||||
return from(this.oauthService.loadUserProfile());
|
||||
}
|
||||
|
||||
public async authenticate(setState: boolean = true): Promise<boolean> {
|
||||
this.oauthService.configure(this.authConfig);
|
||||
|
||||
this.oauthService.strictDiscoveryDocumentValidation = false;
|
||||
await this.oauthService.loadDiscoveryDocumentAndTryLogin();
|
||||
|
||||
this._authenticated = this.oauthService.hasValidAccessToken();
|
||||
|
||||
if (!this.oauthService.hasValidIdToken() || !this.authenticated) {
|
||||
const newState = setState
|
||||
? await this.statehandler.createState().toPromise()
|
||||
: undefined;
|
||||
this.oauthService.initCodeFlow(newState);
|
||||
}
|
||||
this._authenticationChanged.next(this.authenticated);
|
||||
|
||||
return this.authenticated;
|
||||
}
|
||||
|
||||
public signout(): void {
|
||||
this.oauthService.logOut();
|
||||
this._authenticated = false;
|
||||
this._authenticationChanged.next(false);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Our example includes a _StatehandlerService_ to redirect the user back to the route where he initially came from.
|
||||
If you don't need such behavior, you can omit the following line from the `authenticate()` method above.
|
||||
|
||||
```ts
|
||||
...
|
||||
const newState = setState ? await this.statehandler.createState().toPromise() : undefined;
|
||||
...
|
||||
```
|
||||
|
||||
If you decide to use the _StatehandlerService_, provide it in the `app.module`. Make sure it gets initialized first using Angular’s `APP_INITIALIZER`. You find the service implementation in the [example](https://github.com/zitadel/zitadel-examples/tree/main/angular).
|
||||
|
||||
```ts
|
||||
|
||||
const stateHandlerFn = (stateHandler: StatehandlerService) => {
|
||||
return () => {
|
||||
return stateHandler.initStateHandler();
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
providers: [
|
||||
{
|
||||
provide: APP_INITIALIZER,
|
||||
useFactory: stateHandlerFn,
|
||||
multi: true,
|
||||
deps: [StatehandlerService],
|
||||
},
|
||||
{
|
||||
provide: StatehandlerProcessorService,
|
||||
useClass: StatehandlerProcessorServiceImpl,
|
||||
},
|
||||
{
|
||||
provide: StatehandlerService,
|
||||
useClass: StatehandlerServiceImpl,
|
||||
},
|
||||
]
|
||||
...
|
||||
```
|
||||
|
||||
### Add Login to Your Application
|
||||
|
||||
To log a user in, you need a component or a guard.
|
||||
|
||||
- A component could provide a button, starting the login flow on click.
|
||||
|
||||
- A guard that starts a login flow once a user without a stored valid access token tries to access a protected route.
|
||||
|
||||
Using these components heavily depends 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.
|
||||
|
||||
Same for the guard:
|
||||
|
||||
```bash
|
||||
ng g guard guards/auth
|
||||
```
|
||||
|
||||
This code shows the _AuthGuard_ used in ZITADEL Console.
|
||||
|
||||
```ts
|
||||
import { Injectable } from "@angular/core";
|
||||
import {
|
||||
ActivatedRouteSnapshot,
|
||||
CanActivate,
|
||||
RouterStateSnapshot,
|
||||
UrlTree,
|
||||
} from "@angular/router";
|
||||
import { Observable } from "rxjs";
|
||||
import { AuthenticationService } from "../services/authentication.service";
|
||||
|
||||
@Injectable({
|
||||
providedIn: "root",
|
||||
})
|
||||
export class AuthGuard implements CanActivate {
|
||||
constructor(private auth: AuthenticationService) {}
|
||||
|
||||
canActivate(
|
||||
route: ActivatedRouteSnapshot,
|
||||
state: RouterStateSnapshot
|
||||
):
|
||||
| Observable<boolean | UrlTree>
|
||||
| Promise<boolean | UrlTree>
|
||||
| boolean
|
||||
| UrlTree {
|
||||
if (!this.auth.authenticated) {
|
||||
return this.auth.authenticate();
|
||||
}
|
||||
return this.auth.authenticated;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Add the guard to your _RouterModule_ similar to this:
|
||||
|
||||
```ts
|
||||
...
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
loadChildren: () => import('./pages/home/home.module').then(m => m.HomeModule),
|
||||
canActivate: [AuthGuard],
|
||||
},
|
||||
...
|
||||
```
|
||||
|
||||
> Note: Make sure you redirect the user from your callback URL to a guarded page, so `authenticate()` is called again and the access token is stored.
|
||||
|
||||
```ts
|
||||
...
|
||||
{
|
||||
path: 'auth/callback',
|
||||
redirectTo: 'user',
|
||||
},
|
||||
....
|
||||
```
|
||||
|
||||
### Add Logout to Your Application
|
||||
|
||||
Call `auth.signout()` for logging the current user out. Note that you can also configure a logout redirect URI if you want your users to be redirected after logout.
|
||||
|
||||
```ts
|
||||
import { AuthenticationService } from "src/app/services/authentication.service";
|
||||
|
||||
export class SomeComponentWithLogout {
|
||||
constructor(private authService: AuthenticationService) {}
|
||||
|
||||
public signout(): Promise<void> {
|
||||
return this.authService.signout();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Show User Information
|
||||
|
||||
To fetch user data, ZITADEL's user info endpoint has to be called. 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
|
||||
import { AuthenticationService } from 'src/app/services/authentication.service';
|
||||
|
||||
public user$: Observable<any>;
|
||||
|
||||
constructor(private auth: AuthenticationService) {
|
||||
this.user$ = this.auth.getOIDCUser();
|
||||
}
|
||||
```
|
||||
|
||||
And in your HTML file:
|
||||
|
||||
```html
|
||||
<div *ngIf="user$ | async as user">
|
||||
<p>{{user | json}}</p>
|
||||
</div>
|
||||
```
|
||||
|
||||
## Completion
|
||||
|
||||
You have successfully integrated your Angular application with ZITADEL!
|
||||
|
||||
If you get stuck, consider checking out our [example](https://github.com/zitadel/zitadel-examples/tree/main/angular) application. It includes all the mentioned functionality of this quickstart. You can simply start by cloning the repository and replacing the _AuthConfig_ in the _AppModule_ by your own configuration. If you run into 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 to add authorization to your application using ZITADEL APIs. Refer to the [docs](../../apis/introduction) or check out our ZITADEL Console code on [GitHub](https://github.com/zitadel/zitadel) which is using gRPC to access data.
|
||||
|
||||
For more information about creating an Angular application, refer to [Angular](https://angular.io/start) and for more information about the OAuth/OIDC library used above, consider reading their docs at [angular-oauth2-oidc](https://github.com/manfredsteyer/angular-oauth2-oidc).
|
||||
@@ -0,0 +1,413 @@
|
||||
---
|
||||
title: Flutter
|
||||
---
|
||||
|
||||
This guide demonstrates how you integrate **ZITADEL** as an idendity provider to a Flutter app.
|
||||
|
||||
At the end of the guide you have a mobile application on Android and iOS with the ability
|
||||
to authenticate users via ZITADEL.
|
||||
|
||||
If you need any other information about Flutter, head over to the [documentation](https://flutter.dev/).
|
||||
|
||||
## 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 a ZITADEL project
|
||||
|
||||
## Flutter with ZITADEL
|
||||
|
||||
In your native application on ZITADEL, you need to add a callback (redirect) uri
|
||||
which matches the selected custom url scheme. As an example, if you intend to
|
||||
use `ch.myexample.app://sign-me-in` as redirect URI on ZITADEL and in your app,
|
||||
you need to register the `ch.myexample.app://` custom url scheme within Android and iOS.
|
||||
|
||||
:::caution Use Custom Redirect URI!
|
||||
|
||||
You'll need the custom redirect url 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.
|
||||
|
||||
:::
|
||||
|
||||
### Hello World
|
||||
|
||||
After you created the basic Flutter app, the app will show the following screen:
|
||||
|
||||
<div style={{'text-align': 'center', 'margin-bottom': '1rem'}}>
|
||||
<img src="/img/flutter/hello-world.png" alt="Flutter Hello World" height="500px" />
|
||||
</div>
|
||||
|
||||
You may want to change the Flutter SDK version in `pubspec.yaml` from
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
sdk: ">=2.7.0 <3.0.0"
|
||||
```
|
||||
|
||||
to
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
sdk: ">=2.12.0 <3.0.0"
|
||||
```
|
||||
|
||||
With this, you'll enable "nullable by default" mode in Flutter, as well as new language features.
|
||||
For this quickstart, the minimal Flutter SDK version is set to the default: `sdk: ">=2.7.0 <3.0.0"`.
|
||||
|
||||
### 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 open the browser for the login process,
|
||||
the app must open the login page within the embedded browser view
|
||||
|
||||
Install the [`appauth`](https://appauth.io/) package and a secure storage (to store the auth / refresh tokens):
|
||||
|
||||
```bash
|
||||
flutter pub add http
|
||||
flutter pub add flutter_appauth
|
||||
flutter pub add flutter_secure_storage
|
||||
```
|
||||
|
||||
#### Important on Android
|
||||
|
||||
To use this app auth method on Android 11, you'll need to add a `query` to the `AndroidManifest.xml`.
|
||||
Go to `<projectRoot>/android/app/src/main/AndroidManifest.xml` and add to the `<manifest>` root:
|
||||
|
||||
```xml title="<projectRoot>/android/app/src/main/AndroidManifest.xml"
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="https" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.APP_BROWSER" />
|
||||
<data android:scheme="https" />
|
||||
</intent>
|
||||
</queries>
|
||||
```
|
||||
|
||||
This allows the app to query for internal browser activities.
|
||||
|
||||
Furthermore, for `secure_storage`, you need to set the minimum SDK version to 18
|
||||
in `<projectRoot>/android/app/src/build.gradle`. Then, add the manifest placeholder
|
||||
for your redirect url (the custom url scheme). In the end, the `defaultConfig`
|
||||
section of the `build.gradle` file should look like this:
|
||||
|
||||
```groovy title="<projectRoot>/android/app/src/build.gradle"
|
||||
defaultConfig {
|
||||
applicationId "<<YOUR APPLICATION ID, for example ch.myexample.my_fancy_app>>"
|
||||
minSdkVersion 18
|
||||
targetSdkVersion 30
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
manifestPlaceholders = [
|
||||
'appAuthRedirectScheme': '<<YOUR CUSTOM URL SCHEME, for example ch.myexample.app>>'
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Important on iOS
|
||||
|
||||
In a similar way to Android, you need to register the custom url scheme within iOS to
|
||||
be able to use custom redirect schemes. In the `Info.plist` file of the Runner
|
||||
project, you can add the `CFBundleTypeRole` and the `CFBundleUrlSchemes`.
|
||||
|
||||
```xml title="<projectRoot>/ios/Runner/Info.plist"
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>YOUR CUSTOM URL SCHEME, for example ch.myexample.app</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
```
|
||||
|
||||
### Add Authentication
|
||||
|
||||
:::note
|
||||
|
||||
The auth redirect scheme "`ch.myexample.app`" does register all auth urls with the given
|
||||
scheme for the app. So an url pointing to `ch.myexample.app://signin` and another one
|
||||
for `ch.myexample.app://logout` will work with the same registration.
|
||||
|
||||
:::
|
||||
|
||||
To reduce the commented default code, we will modify the `main.dart` file.
|
||||
|
||||
First, the `MyApp` class: it remains a stateless widget:
|
||||
|
||||
```dart
|
||||
class MyApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Flutter ZITADEL',
|
||||
theme: ThemeData(
|
||||
primarySwatch: Colors.blue,
|
||||
),
|
||||
home: MyHomePage(title: 'Flutter ZITADEL Quickstart'),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Second, the `MyHomePage` class will remain a stateful widget with
|
||||
its title, we don't change any code here.
|
||||
|
||||
```dart
|
||||
class MyHomePage extends StatefulWidget {
|
||||
MyHomePage({Key key, this.title}) : super(key: key);
|
||||
|
||||
final String title;
|
||||
|
||||
@override
|
||||
_MyHomePageState createState() => _MyHomePageState();
|
||||
}
|
||||
```
|
||||
|
||||
What we'll change now, is the `_MyHomePageState` class to enable
|
||||
authentication via ZITADEL and remove the counter button of the hello
|
||||
world application. We'll show the username of the authenticated user.
|
||||
|
||||
We define the needed elements for our state:
|
||||
|
||||
```dart
|
||||
final _appAuth = FlutterAppAuth();
|
||||
final _secureStorage = const FlutterSecureStorage();
|
||||
|
||||
var _busy = false;
|
||||
var _authenticated = false;
|
||||
var _username = '';
|
||||
```
|
||||
|
||||
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
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(widget.title),
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (!_authenticated && !_busy)
|
||||
Text(
|
||||
'You are not authenticated.',
|
||||
),
|
||||
if (!_authenticated && !_busy)
|
||||
ElevatedButton.icon(
|
||||
icon: Icon(Icons.fingerprint),
|
||||
label: Text('login'),
|
||||
onPressed: _authenticate),
|
||||
if (_busy)
|
||||
Stack(
|
||||
children: [
|
||||
Center(child: Text("Busy, logging in.")),
|
||||
Opacity(
|
||||
opacity: 0.5,
|
||||
child: Container(
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
Center(child: CircularProgressIndicator()),
|
||||
],
|
||||
),
|
||||
if (_authenticated && !_busy)
|
||||
Text(
|
||||
'Hello $_username!',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
And finally the `_authenticate` method which calls the authorization endpoint,
|
||||
then fetches the user info and stores the tokens into the secure storage.
|
||||
|
||||
```dart
|
||||
Future<void> _authenticate() async {
|
||||
setState(() {
|
||||
_busy = true;
|
||||
});
|
||||
|
||||
try {
|
||||
final result = await _appAuth.authorizeAndExchangeCode(
|
||||
AuthorizationTokenRequest(
|
||||
'<<CLIENT_ID>>', // Client ID of the native application
|
||||
'<<CALLBACK_URL>>', // The registered url from zitadel (e.g. ch.myexample.app://signin)
|
||||
issuer: '<<ISSUER>>', // most of the cases: https:/[your-domain]-[random-string].zitadel.cloud
|
||||
scopes: [
|
||||
'openid',
|
||||
'profile',
|
||||
'email',
|
||||
'offline_access',
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final userInfoResponse = await get(
|
||||
Uri.parse('https://[your-instance].zitadel.cloud/oidc/v1/userinfo'),
|
||||
headers: {
|
||||
HttpHeaders.authorizationHeader: 'Bearer ${result.accessToken}',
|
||||
HttpHeaders.acceptHeader: 'application/json; charset=UTF-8'
|
||||
},
|
||||
);
|
||||
final userJson = jsonDecode(utf8.decode(userInfoResponse.bodyBytes));
|
||||
|
||||
await _secureStorage.write(
|
||||
key: 'auth_access_token', value: result?.accessToken);
|
||||
await _secureStorage.write(
|
||||
key: 'refresh_token', value: result?.refreshToken);
|
||||
await _secureStorage.write(key: 'id_token', value: result?.idToken);
|
||||
|
||||
setState(() {
|
||||
_busy = false;
|
||||
_authenticated = true;
|
||||
_username = '${userJson['given_name']} ${userJson['family_name']}';
|
||||
});
|
||||
} catch (e, s) {
|
||||
print('error on authorizeAndExchangeCode token: $e - stack: $s');
|
||||
setState(() {
|
||||
_busy = false;
|
||||
_authenticated = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Now, you should be able to login with a valid ZITADEL user.
|
||||
|
||||
#### Result
|
||||
|
||||
In the end, our state class looks like:
|
||||
|
||||
```dart
|
||||
class _MyHomePageState extends State<MyHomePage> {
|
||||
final _appAuth = FlutterAppAuth();
|
||||
final _secureStorage = const FlutterSecureStorage();
|
||||
|
||||
var _busy = false;
|
||||
var _authenticated = false;
|
||||
var _username = '';
|
||||
|
||||
Future<void> _authenticate() async {
|
||||
setState(() {
|
||||
_busy = true;
|
||||
});
|
||||
|
||||
try {
|
||||
final result = await _appAuth.authorizeAndExchangeCode(
|
||||
AuthorizationTokenRequest(
|
||||
'CLIENT_ID',
|
||||
'CALLBACK_URL',
|
||||
issuer: 'ISSUER',
|
||||
scopes: [
|
||||
'openid',
|
||||
'profile',
|
||||
'email',
|
||||
'offline_access',
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final userInfoResponse = await get(
|
||||
Uri.parse('https:/[your-domain]-[random-string].zitadel.cloud/oidc/v1/userinfo'), // replace with your instance
|
||||
headers: {
|
||||
HttpHeaders.authorizationHeader: 'Bearer ${result.accessToken}',
|
||||
HttpHeaders.acceptHeader: 'application/json; charset=UTF-8'
|
||||
},
|
||||
);
|
||||
final userJson = jsonDecode(utf8.decode(userInfoResponse.bodyBytes));
|
||||
|
||||
await _secureStorage.write(
|
||||
key: 'auth_access_token', value: result?.accessToken);
|
||||
await _secureStorage.write(
|
||||
key: 'refresh_token', value: result?.refreshToken);
|
||||
await _secureStorage.write(key: 'id_token', value: result?.idToken);
|
||||
|
||||
setState(() {
|
||||
_busy = false;
|
||||
_authenticated = true;
|
||||
_username = '${userJson['given_name']} ${userJson['family_name']}';
|
||||
});
|
||||
} catch (e, s) {
|
||||
print('error on authorizeAndExchangeCode token: $e - stack: $s');
|
||||
setState(() {
|
||||
_busy = false;
|
||||
_authenticated = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(widget.title),
|
||||
),
|
||||
body: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (!_authenticated && !_busy)
|
||||
Text(
|
||||
'You are not authenticated.',
|
||||
),
|
||||
if (!_authenticated && !_busy)
|
||||
ElevatedButton.icon(
|
||||
icon: Icon(Icons.fingerprint),
|
||||
label: Text('login'),
|
||||
onPressed: _authenticate),
|
||||
if (_busy)
|
||||
Stack(
|
||||
children: [
|
||||
Center(child: Text("Busy, logging in.")),
|
||||
Opacity(
|
||||
opacity: 0.5,
|
||||
child: Container(
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
Center(child: CircularProgressIndicator()),
|
||||
],
|
||||
),
|
||||
if (_authenticated && !_busy)
|
||||
Text(
|
||||
'Hello $_username!',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
If you run this application, you can authenticate with a valid ZITADEL user.
|
||||
|
||||
<div style={{display: 'grid', 'grid-column-gap': '1rem', 'grid-template-columns': '1fr 1fr'}}>
|
||||
<img src="/img/flutter/not-authed.png" alt="Unauthenticated" height="500px" />
|
||||
<img src="/img/flutter/authed.png" alt="Flutter Authenticated" height="500px" />
|
||||
</div>
|
||||
@@ -0,0 +1,163 @@
|
||||
---
|
||||
title: 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-example repo. Take a look [here](https://github.com/zitadel/zitadel-examples/tree/main/nextjs).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, we start by creating a new NextJS app with `npx create-next-app`, which sets up everything automatically for you. To create a project, run:
|
||||
|
||||
```bash
|
||||
npx create-next-app --typescript
|
||||
# or
|
||||
yarn create next-app --typescript
|
||||
```
|
||||
|
||||
# Install Authentication library
|
||||
|
||||
To keep the template as easy as possible we use [next-auth](https://next-auth.js.org/) as our main authentication library. To install, run:
|
||||
|
||||
```bash
|
||||
npm i next-auth
|
||||
# or
|
||||
yarn add next-auth
|
||||
```
|
||||
|
||||
To run the app, type:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
then open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
# Configuration
|
||||
|
||||
NextAuth.js exposes a REST API which is used by your client.
|
||||
To setup your configuration, create a file called [...nextauth].tsx in `pages/api/auth`.
|
||||
|
||||
```ts
|
||||
import NextAuth from "next-auth";
|
||||
|
||||
export const ZITADEL = {
|
||||
id: "zitadel",
|
||||
name: "zitadel",
|
||||
type: "oauth",
|
||||
version: "2",
|
||||
wellKnown: process.env.ZITADEL_ISSUER,
|
||||
authorization: {
|
||||
params: {
|
||||
scope: "openid email profile",
|
||||
},
|
||||
},
|
||||
idToken: true,
|
||||
checks: ["pkce", "state"],
|
||||
client: {
|
||||
token_endpoint_auth_method: "none",
|
||||
},
|
||||
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,
|
||||
};
|
||||
},
|
||||
clientId: process.env.ZITADEL_CLIENT_ID,
|
||||
};
|
||||
|
||||
export default NextAuth({
|
||||
providers: [ZITADEL],
|
||||
});
|
||||
```
|
||||
|
||||
Replace the endpoints `https:/[your-domain]-[random-string].zitadel.cloud` with your instance or if your using a ZITADEL CLOUD tier or your own endpoint if your using a self hosted ENTERPRISE tier respectively.
|
||||
|
||||
We recommend using the Authentication Code flow secured by PKCE for the Authentication flow.
|
||||
To be able to connect to ZITADEL, navigate to your Console Projects, create or select an existing project and add your app selecting WEB, then PKCE, and then 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.
|
||||
|
||||
> Note that we get a clientId but no clientSecret because it is not needed for our authentication flow.
|
||||
|
||||
## Environment
|
||||
|
||||
Create a file `.env` in the root of the project and add the following keys to it.
|
||||
|
||||
```
|
||||
NEXTAUTH_URL=http://localhost:3000
|
||||
ZITADEL_CLIENT_ID=[yourClientId]
|
||||
ZITADEL_ISSUER=https:/[your-domain]-[random-string].zitadel.cloud
|
||||
```
|
||||
|
||||
# User interface
|
||||
|
||||
Now we can start editing the homepage by modifying `pages/index.tsx`.
|
||||
Add this snippet your file. This code gets your auth session from next-auth, renders a Logout button if your authenticated or shows a Signup button if your not.
|
||||
Note that signIn method requires the id of the provider we provided earlier, and provides a possibilty to add a callback url, Auth Next will redirect you to the specified route if logged in successfully.
|
||||
|
||||
```ts
|
||||
import { signIn, signOut, useSession } from 'next-auth/client';
|
||||
|
||||
export default function Page() {
|
||||
const { data: session } = useSession();
|
||||
...
|
||||
{!session && <>
|
||||
Not signed in <br />
|
||||
<button onClick={() => signIn('zitadel', { callbackUrl: 'http://localhost:3000/profile' })}>
|
||||
Sign in
|
||||
</button>
|
||||
</>}
|
||||
{session && <>
|
||||
Signed in as {session.user.email} <br />
|
||||
<button onClick={() => signOut()}>Sign out</button>
|
||||
</>}
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
### 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 `/pages/_app.tsx`.
|
||||
Take a loot at the template `_app.tsx`.
|
||||
|
||||
```ts
|
||||
import { SessionProvider } from "next-auth/react";
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
return (
|
||||
<SessionProvider session={pageProps.session}>
|
||||
<Component {...pageProps} />
|
||||
</SessionProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default MyApp;
|
||||
```
|
||||
|
||||
Last thing: create a `profile.tsx` in /pages which renders the callback page.
|
||||
|
||||
```ts
|
||||
import Link from "next/link";
|
||||
|
||||
import styles from "../styles/Home.module.css";
|
||||
|
||||
export default function Profile() {
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<h1>Login successful</h1>
|
||||
<Link href="/">
|
||||
<button>Back to Home</button>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,117 @@
|
||||
---
|
||||
title: React
|
||||
---
|
||||
|
||||
This Integration guide shows you the recommended way to integrate **ZITADEL** into your React Application.
|
||||
It demonstrates how to add a user login to your application and fetch some data from the user info endpoint.
|
||||
|
||||
At the end of the guide you should have an application able to login a user and read the user profile.
|
||||
|
||||
## 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. 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 User Agent and continue. More about the different app types can you find [here](https://docs.zitadel.com/docs/guides/authorization/oauth-recommended-flows#different-client-profiles).
|
||||
We recommend that you use [Authorization Code](../../apis/openidoauth/grant-types#authorization-code) in combination with [Proof Key for Code Exchange](../../apis/openidoauth/grant-types#proof-key-for-code-exchange) for all web applications.
|
||||
|
||||
### 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 app will be deployed to or use `http://localhost:3000/` because this will be the default of npm.
|
||||
|
||||
> You should 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
|
||||
|
||||
After successful app creation a popup will appear showing you your clientID.
|
||||
Copy your client ID as it will be needed in the next step.
|
||||
|
||||
## React Setup
|
||||
|
||||
### Create React app
|
||||
|
||||
Create a new React app with the following command
|
||||
|
||||
```bash
|
||||
npx create-react-app my-app
|
||||
```
|
||||
|
||||
### Install oidc client
|
||||
|
||||
You need to install an oauth / oidc client to connect with ZITADEL. Run the following command:
|
||||
|
||||
```bash
|
||||
npm install oidc-react
|
||||
```
|
||||
|
||||
This library helps integrating ZITADEL Authentication in your React Application.
|
||||
|
||||
### Create and configure Auth Module
|
||||
|
||||
With the installed oidc pakage you will need an AuthProvider which should contain the OIDC configuration.
|
||||
|
||||
The oidc configuration should contain **openid**, **profile** and **email** as scope and **code** as responseType.
|
||||
In the code below make sure to change the issuer to your instance url. You can find this in the ZITADEL Console on you application.
|
||||
Replace the clientId value 'YOUR-CLIENT-ID' with the generated client id of you application in ZITADEL Console.
|
||||
|
||||
```ts
|
||||
import React from "react";
|
||||
import { AuthProvider } from "oidc-react";
|
||||
import "./App.css";
|
||||
const oidcConfig = {
|
||||
onSignIn: async (response: any) => {
|
||||
alert(
|
||||
"You logged in :" +
|
||||
response.profile.given_name +
|
||||
" " +
|
||||
response.profile.family_name
|
||||
);
|
||||
window.location.hash = "";
|
||||
},
|
||||
authority: "https:/[your-domain]-[random-string].zitadel.cloud", // replace with your instance
|
||||
clientId: "YOUR-CLIENT-ID",
|
||||
responseType: "code",
|
||||
redirectUri: "http://localhost:3000/",
|
||||
scope: "openid profile email",
|
||||
};
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<AuthProvider {...oidcConfig}>
|
||||
<div className="App">
|
||||
<header className="App-header">
|
||||
<p>Hello World</p>
|
||||
</header>
|
||||
</div>
|
||||
</AuthProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
```
|
||||
|
||||
### Run application
|
||||
|
||||
Start your react application with the following command
|
||||
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
|
||||
Your browser should automatically open the app site or just go to `http://localhost:3000/`.
|
||||
On opening the app in the browser you will be redirected to the login of your instance.
|
||||
After successfully authenticating your user, you will get back to you application.
|
||||
It should show a popup which says: **You logged in {FirstName} {LastName}**
|
||||
|
||||
## Completion
|
||||
|
||||
You have successfully integrated ZITADEL in your React Application!
|
||||
|
||||
### Whats next?
|
||||
|
||||
Now you can proceed implementing our APIs to include Authorization. You can find our API Docs [here](../../apis/introduction)
|
||||
|
||||
For more information about creating a React application we refer to [React](https://reactjs.org/docs/getting-started.html) and for more information about the used oauth/oidc library consider reading their docs at [oidc-react](https://www.npmjs.com/package/oidc-react).
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
title: .NET
|
||||
---
|
||||
Coming soon
|
||||
@@ -0,0 +1,150 @@
|
||||
---
|
||||
title: 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.
|
||||
|
||||
At the end of the guide you should have an API with a protected endpoint.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
The client [SDK](https://github.com/zitadel/zitadel-go) will provides an interceptor for both GRPC and HTTP.
|
||||
This will handle the OAuth 2.0 introspection request including authentication using JWT with Private Key using our [OIDC client library](https://github.com/zitadel/oidc).
|
||||
All that is required, is an API and its key JSON. But for complete
|
||||
|
||||
## Go Setup
|
||||
|
||||
### Add Go SDK to your project
|
||||
|
||||
You need to add the SDK into Go Modules by:
|
||||
|
||||
```bash
|
||||
go get github.com/zitadel/zitadel-go/v2
|
||||
```
|
||||
|
||||
### Create example API
|
||||
|
||||
Create a new go file with the content below. This will create an API with two endpoints. On path `/public` it will always write
|
||||
back `ok` and the current timestamp. On `/protected` it will respond the same but only if a valid access_token is sent. The token
|
||||
must not be expired and the API has to be part of the audience (either client_id or project_id).
|
||||
|
||||
Make sure to fill the var `issuer` with your own domain. This is the domain of your instance you can find it on the instance detail in the ZITADEL Cloud Customer Portal or in the ZITADEL Console.
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
http_mw "github.com/zitadel/zitadel-go/v2/pkg/api/middleware/http"
|
||||
"github.com/zitadel/zitadel-go/v2/pkg/client/middleware"
|
||||
)
|
||||
|
||||
var (
|
||||
issuer = flag.String("issuer", "", "issuer of your ZITADEL instance (in the form: https://<instance>.zitadel.cloud or https://<yourdomain>)")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
introspection, err := http_mw.NewIntrospectionInterceptor(*issuer, middleware.OSKeyPath())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
router := http.NewServeMux()
|
||||
router.HandleFunc("/public", writeOK)
|
||||
router.HandleFunc("/protected", introspection.HandlerFunc(writeOK))
|
||||
|
||||
lis := "127.0.0.1:5001"
|
||||
log.Fatal(http.ListenAndServe(lis, router))
|
||||
}
|
||||
|
||||
func writeOK(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("OK " + time.Now().String()))
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### Key JSON
|
||||
|
||||
To provide the key JSON to the SDK, simply set an environment variable `ZITADEL_KEY_PATH` with the path to the JSON as value.
|
||||
|
||||
```bash
|
||||
export ZITADEL_KEY_PATH=/Users/test/apikey.json
|
||||
```
|
||||
|
||||
For development purposes you should be able to set this in your IDE.
|
||||
|
||||
If you're not able to set it via environment variable, you can also exchange the `middleware.OSKeyPath()` and pass it directly:
|
||||
|
||||
```go
|
||||
introspection, err := http_mw.NewIntrospectionInterceptor(
|
||||
client.Issuer,
|
||||
"/Users/test/apikey.json",
|
||||
)
|
||||
```
|
||||
|
||||
### Test API
|
||||
|
||||
After you have configured everything correctly, you can simply start the example by:
|
||||
|
||||
```bash
|
||||
go run main.go
|
||||
```
|
||||
|
||||
You can now call the API by browser or curl. Try the public endpoint first:
|
||||
|
||||
```bash
|
||||
curl -i localhost:5001/public
|
||||
```
|
||||
|
||||
it should return something like:
|
||||
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Date: Tue, 24 Aug 2021 11:11:17 GMT
|
||||
Content-Length: 59
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
|
||||
OK 2021-08-24 13:11:17.135719 +0200 CEST m=+30704.913892168
|
||||
```
|
||||
|
||||
and the protected:
|
||||
|
||||
```bash
|
||||
curl -i localhost:5001/protected
|
||||
```
|
||||
|
||||
it will return:
|
||||
|
||||
```
|
||||
HTTP/1.1 401 Unauthorized
|
||||
Content-Type: application/json
|
||||
Date: Tue, 24 Aug 2021 11:13:10 GMT
|
||||
Content-Length: 21
|
||||
|
||||
"auth header missing"
|
||||
```
|
||||
|
||||
Get a valid access_token for the API. You can achieve this by login into an application of the same project or
|
||||
by explicitly requesting the project_id for the audience by scope `urn:zitadel:iam:org:project:id:{projectid}:aud`.
|
||||
|
||||
If you provide a valid Bearer Token:
|
||||
|
||||
```bash
|
||||
curl -i -H "Authorization: Bearer ${token}" localhost:5001/protected
|
||||
```
|
||||
|
||||
it will return an OK response as well:
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Date: Tue, 24 Aug 2021 11:13:33 GMT
|
||||
Content-Length: 59
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
|
||||
OK 2021-08-24 13:13:33.131943 +0200 CEST m=+30840.911149251
|
||||
```
|
||||
Reference in New Issue
Block a user