docs: add tailwindcss for styles, oidc authorize endpoint playground (#4707)

* variable parser

* rm plugin

* set fcn

* env

* EnvCode component

* cleanup env demo

* env

* rm remark plugin

* auth request context

* auth req component

* authorize endpoint construction

* rev react page

* fix endpoint

* styling

* query params with anchor

* desc

* tailwind coexistence

* fix styles

* add login_hint, organizationId scope

* auth request without prompt

* show login_hint

* sync displayed url with actual href

* fix fcn

* coloring

* Update docs/src/components/authrequest.jsx

Co-authored-by: mffap <mpa@zitadel.com>

* Update docs/src/components/authrequest.jsx

Co-authored-by: mffap <mpa@zitadel.com>

* Update docs/src/components/authrequest.jsx

Co-authored-by: mffap <mpa@zitadel.com>

* Update docs/src/components/authrequest.jsx

Co-authored-by: mffap <mpa@zitadel.com>

* Update docs/src/components/authrequest.jsx

Co-authored-by: mffap <mpa@zitadel.com>

* Update docs/src/components/authrequest.jsx

Co-authored-by: mffap <mpa@zitadel.com>

* add plausible, header

* add pkce

* move

* adds pkce code challenge

* replace cboa

* reaname and move to required

* fall back to cboa due to webpack error

* trailing slash

* reorder org_id

* remove resourceowner

* texts

* update references

* buffer, fix some react dom components

* Apply suggestions from code review

Co-authored-by: Florian Forster <florian@zitadel.com>

* standard scopes

Co-authored-by: mffap <mpa@zitadel.com>
Co-authored-by: Florian Forster <florian@zitadel.com>
This commit is contained in:
Max Peintner 2022-12-05 18:36:12 +01:00 committed by GitHub
parent add232d1dd
commit 97fe041a86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1654 additions and 459 deletions

View File

@ -34,7 +34,7 @@ The easiest way to have a look at them is, to import them in the [Swagger Editor
The authentication API (aka Auth API) is used for all operations on the currently logged in user. The user id is taken from the sub claim in the token.
</div>
<div class="apicard-right">
<div className="apicard-right">
### GRPC
@ -70,7 +70,7 @@ The management API is as the name states the interface where systems can mutate
To identify the current organization you can send a header `x-zitadel-orgid` or if no header is set, the organization of the authenticated user is set.
</div>
<div class="apicard-right">
<div className="apicard-right">
### GRPC
@ -104,7 +104,7 @@ Definition:
This API is intended to configure and manage one ZITADEL instance itself.
</div>
<div class="apicard-right">
<div className="apicard-right">
### GRPC
@ -140,7 +140,7 @@ This API is intended to manage the different ZITADEL instances within the system
Checkout the guide how to [access the ZITADEL System API](/docs/guides/integrate/access-zitadel-system-api).
</div>
<div class="apicard-right">
<div className="apicard-right">
### GRPC
@ -209,9 +209,9 @@ As you can see the `GetMyUser` function is also available as a REST service unde
In the table below you can see the URI of those calls.
| Service | URI |
| :------ | :--------------------------------------------------------------------------------------------------------------------------------------------- |
| REST | {your_domain}/auth/v1/users/me |
| Service | URI |
| :------ | :-------------------------------------------------- |
| REST | {your_domain}/auth/v1/users/me |
| GRPC | {your_domain}/zitadel.auth.v1.AuthService/GetMyUser |
## Domains

View File

@ -0,0 +1,115 @@
---
title: OIDC Authentication Request Playground
sidebar_label: OIDC Playground
---
import { SetAuthRequest } from "../../../src/components/authrequest";
The OIDC Playground is for testing OpenID Authentication Requests, giving you more insight how OpenID Connect works and how you can customize ZITADEL behavior with different parameters.
An OpenID Connect (OIDC) [authentication request](https://openid.net/specs/openid-connect-core-1_0.html) is an OAuth 2.0 Authorization Request using additional parameters and scopes to request that the end-user be authenticated by ZITADEL.
<SetAuthRequest />
## Why this OIDC playground?
Currently ZITADEL requires human users to authenticate trough the hosted login page.
Your application should initiate a login by issuing an authentication request and redirecting the user to the login page. You can customize the behavior of ZITADEL by providing additional parameters and scopes in the request.
This playground should help you to initially craft an authentication request and to explore the behavior of ZITADEL in more depth.
## Request parameters explained
Not all request parameters are available in the playground. Please refer to the full documentation of the [authorization endpoint](/docs/apis/openidoauth/endpoints#authorization_endpoint).
### Your Domain
The <span className="text-yellow-500">Instance Domain</span> to your ZITADEL instance. Use the base-path, the playground will add the required path to the request.
### Required Parameters
<p>
<span className="text-green-500">Client ID</span> is the resource id of an
application. It's the application where you want your users to login. You can
find the resource id in the Console. When using organization grants, use the
client id from the origin organization.
</p>
<p>
<span className="text-blue-500">Redirect URI</span> be one of the
pre-configured redirect uris for your application. You must add the redirect
uri for your application, else you will receive an error.
</p>
<p>
<span className="text-orange-500">Response Type</span> defines whether a
code, id_token token or just id_token will be returned. Most use cases will
need code.
</p>
More in the <a href="/docs/apis/openidoauth/endpoints#required-request-parameters">documentation</a> about required Parameters.
### Authentication methods
Depending on the authentication and authorization flow of your application you might need to append some information to the authentication request.
<span className="text-teal-600">Authentication method</span> "(none) PKCE" is recommended
for most application types. The playground appends automatically a code challenge
for PKCE flows.
You need to append a "Code Challenge" by providing a random <span className="text-teal-600">Code Verifier</span> that is being hashed and encoded in the request to the token endpoint, please see our [guide](/docs/guides/integrate/login-users#token-request) for more details.
More in the [documentation](/docs/apis/openidoauth/authn-methods) about authentication methods.
### Additional Parameters
<p>
<span className="text-cyan-500">Prompt</span> defines if and how the user
should be prompted on login. For example you can pre-select a login name (
<code>select_account</code>) or present the register form (<code>create</code>
) to users directly. The value <code>login</code> requires the user to
re-authenticate.
</p>
<p>
<span className="text-rose-500">Login hint</span> must be a valid logon name
of a user. You can skip the account picker by providing the Login hint.
</p>
There are many more additional parameters. Please refer to the [documentation](/docs/apis/openidoauth/endpoints#additional-parameters) about additional parameters.
## Standard Scopes
Used to request additional information from ZITADEL.
These scopes are defined in the OpenID Connect specification.
The `openid` scope is mandatory.
Not all scopes are available in the playground. Please refer to the full [documentation](/docs/apis/openidoauth/scopes) for the exhaustive list of available standard and reserved scopes.
## Reserved Scopes
You can request additional information that is specific to ZITADEL or customize the behavior of ZITADEL by including reserved scopes.
Please refer to the [documentation](/docs/apis/openidoauth/scopes#reserved-scopes) for a full list of available reserved scopes.
### Organization policies and branding
Enforce an organization's policies and branding as well as membership of the user by passing the scope `urn:zitadel:iam:org:id:{id}` with the required <span className="text-purple-500">Organization ID</span>.
Please refer to the full [guide on branding](/docs/guides/manage/customize/branding).
### Get user metadata
Pass the scope `urn:zitadel:iam:user:metadata` to request a user's metadata.
Please refer to the full [guide on user-metadata](/docs/guides/manage/customize/user-metadata) for further details.
### Access core apis
Calling the [core API](/docs/apis/introduction) with the authenticated user, requires that the projectID of ZITADEL is included in the audience claim.
This can be achieved by adding the scope `urn:zitadel:iam:org:project:id:zitadel:aud` to your applications authorization request.
## How to use ZITADEL in your project
Please refer to our [guide](/docs/guides/integrate/login-users) on how to login users.
OpenID Connect certified libraries should allow you to customize the parameters and define scopes for the authorization request. You can also continue by using one of our [example applications](/docs/examples/introduction).

View File

@ -2,13 +2,13 @@
title: Endpoints
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
## OpenID Connect 1.0 Discovery
The OpenID Connect Discovery Endpoint is located within the issuer domain.
This would give us {your_domain}/.well-known/openid-configuration.
This would give us {your_domain}/.well-known/openid-configuration.
**Link to spec.** [OpenID Connect Discovery 1.0 incorporating errata set 1](https://openid.net/specs/openid-connect-discovery-1_0.html)
@ -21,28 +21,36 @@ The authorization_endpoint is located with the login page, due to the need of ac
:::
The authorization_endpoint is the starting point for all initial user authentications. The user agent (browser) will be redirected to this endpoint to
authenticate the user in exchange for an authorization_code (authorization code flow) or tokens (implicit flow).
authenticate the user in exchange for an authorization_code (authorization code flow) or tokens (implicit flow).
<details>
<summary>Links to specs</summary>
<ul>
<li><a href="https://datatracker.ietf.org/doc/html/rfc6749#section-3.1">Section 3.1 of OAuth2.0 (RFC6749)</a></li>
<li><a href="https://openid.net/specs/openid-connect-core-1_0.html#AuthorizationEndpoint">Section 3.1.2 of OpenID Connect Core 1.0 incorporating errata set 1</a></li>
</ul>
<summary>Links to specs</summary>
<ul>
<li>
<a href="https://datatracker.ietf.org/doc/html/rfc6749#section-3.1">
Section 3.1 of OAuth2.0 (RFC6749)
</a>
</li>
<li>
<a href="https://openid.net/specs/openid-connect-core-1_0.html#AuthorizationEndpoint">
Section 3.1.2 of OpenID Connect Core 1.0 incorporating errata set 1
</a>
</li>
</ul>
</details>
### Required request parameters
| Parameter | Description |
|---------------|---------------------------------------------------------------------------------------------------------------------------------------------------|
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| client_id | The id of your client as shown in Console. |
| redirect_uri | Callback uri of the authorization request where the code or tokens will be sent to. Must match exactly one of the preregistered in Console. |
| response_type | Determines whether a `code`, `id_token token` or just `id_token` will be returned. Most use cases will need `code`. See flow guide for more info. |
| scope | `openid` is required, see [Scopes](scopes) for more possible values. Scopes are space delimited, e.g. `openid email profile` |
:::important
Following the [OIDC Core 1.0 specs](https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims) whenever an access_token is issued,
the id_token will not contain any claims of the scopes `profile`, `email`, `phone` and `address`.
Following the [OIDC Core 1.0 specs](https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims) whenever an access_token is issued,
the id_token will not contain any claims of the scopes `profile`, `email`, `phone` and `address`.
Send the access_token to the [userinfo_endpoint](#userinfo_endpoint) or [introspection_endpoint](#introspection_endpoint) the retrieve these claims
or set the `id_token_userinfo_assertion` Option ("User Info inside ID Token" in Console) to true.
@ -69,7 +77,7 @@ no additional parameters required
<TabItem value="none">
| Parameter | Description |
|-----------------------|-------------------------------------------------------|
| --------------------- | ----------------------------------------------------- |
| code_challenge | The SHA-256 value of the generated `code_verifier` |
| code_challenge_method | Method used to generate the challenge, must be `S256` |
@ -84,7 +92,7 @@ no additional parameters required
### Additional parameters
| Parameter | Description |
|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| id_token_hint | Valid `id_token` (of an existing session) used to identity the subject. **SHOULD** be provided when using prompt `none`. |
| login_hint | A valid logon name of a user. Will be used for username inputs or preselecting a user on `select_account`. Be sure to encode the hint correctly using url encoding (especially when using `+` or alike in the loginname) |
| max_age | Seconds since the last active successful authentication of the user |
@ -95,10 +103,10 @@ no additional parameters required
### Successful Code Response
When your `response_type` was `code` and no error occurred, the following response will be returned:
When your `response_type` was `code` and no error occurred, the following response will be returned:
| Property | Description |
|----------|-------------------------------------------------------------------------------|
| -------- | ----------------------------------------------------------------------------- |
| code | Opaque string which will be necessary to request tokens on the token endpoint |
| state | Unmodified `state` parameter from the request |
@ -107,7 +115,7 @@ When your `response_type` was `code` and no error occurred, the following respon
When your `response_type` was either `it_token` or `id_token token` and no error occurred, the following response will be returned:
| Property | Description |
|--------------|---------------------------------------------------------------------------------------|
| ------------ | ------------------------------------------------------------------------------------- |
| access_token | Only returned if `response_type` included `token` |
| expires_in | Number of second until the expiration of the `access_token` |
| id_token | An `id_token` of the authorized user |
@ -125,7 +133,7 @@ the error will be display directly to the user on the auth server
:::
| Property | Description |
|-------------------|----------------------------------------------------------------------|
| ----------------- | -------------------------------------------------------------------- |
| error | An OAuth / OIDC [error_type](#authorize-errors) |
| error_description | Description of the error type or additional information of the error |
| state | Unmodified `state` parameter from the request |
@ -133,7 +141,7 @@ the error will be display directly to the user on the auth server
#### Possible errors {#authorize-errors}
| error_type | Possible reason |
|---------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| invalid_request | The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed. |
| invalid_scope | The requested scope is invalid. Typically the required `openid` value is missing. |
| unauthorized_client | The client is not authorized to request an access_token using this method. Check in Console that the requested `response_type` is allowed in your application configuration. |
@ -142,12 +150,11 @@ the error will be display directly to the user on the auth server
| interaction_required | The authorization server requires end-user interaction of some form to proceed. This error MAY be returned when the prompt parameter value in the Authentication Request is none, but the Authentication Request cannot be completed without displaying a user interface for end-user interaction. |
| login_required | The authorization server requires end-user authentication. This error MAY be returned when the prompt parameter value in the Authentication Request is none, but the Authentication Request cannot be completed without displaying a user interface for end-user authentication. |
## token_endpoint
{your_domain}/oauth/v2/token
The token_endpoint will as the name suggests return various tokens (access, id and refresh) depending on the used `grant_type`.
The token_endpoint will as the name suggests return various tokens (access, id and refresh) depending on the used `grant_type`.
When using [`authorization_code`](#authorization-code-grant-code-exchange) flow call this endpoint after receiving the code from the authorization_endpoint.
When using [`refresh_token`](#authorization-code-grant-code-exchange) or [`urn:ietf:params:oauth:grant-type:jwt-bearer` (JWT Profile)](#jwt-profile-grant) you will call this endpoint directly.
@ -158,7 +165,7 @@ As mention above, when using `authorization_code` grant, this endpoint will be y
#### Required request Parameters
| Parameter | Description |
|--------------|---------------------------------------------------------------------------------------------------------------|
| ------------ | ------------------------------------------------------------------------------------------------------------- |
| code | Code that was issued from the authorization request. |
| grant_type | Must be `authorization_code` |
| redirect_uri | Callback uri where the code was be sent to. Must match exactly the redirect_uri of the authorization request. |
@ -185,7 +192,7 @@ Send your `client_id` and `client_secret` as Basic Auth Header. Check [Client Se
Send your `client_id` and `client_secret` as parameters in the body:
| Parameter | Description |
|---------------|----------------------------------|
| ------------- | -------------------------------- |
| client_id | client_id of the application |
| client_secret | client_secret of the application |
@ -195,7 +202,7 @@ Send your `client_id` and `client_secret` as parameters in the body:
Send your `code_verifier` for us to recompute the `code_challenge` of the authorization request.
| Parameter | Description |
|---------------|--------------------------------------------------------------|
| ------------- | ------------------------------------------------------------ |
| code_verifier | code_verifier previously used to generate the code_challenge |
</TabItem>
@ -204,7 +211,7 @@ Send your `code_verifier` for us to recompute the `code_challenge` of the author
Send a client assertion as JWT for us to validate the signature against the registered public key.
| Parameter | Description |
|-----------------------|--------------------------------------------------------------------------------------------------------------|
| --------------------- | ------------------------------------------------------------------------------------------------------------ |
| client_assertion | JWT built and signed according to [Using JWTs for Client Authentication](authn-methods#jwt-with-private-key) |
| client_assertion_type | Must be `urn:ietf:params:oauth:client-assertion-type:jwt-bearer` |
@ -214,7 +221,7 @@ Send a client assertion as JWT for us to validate the signature against the regi
#### Successful code response {#token-code-response}
| Property | Description |
|---------------|---------------------------------------------------------------------------------------|
| ------------- | ------------------------------------------------------------------------------------- |
| access_token | An `access_token` as JWT or opaque token |
| expires_in | Number of second until the expiration of the `access_token` |
| id_token | An `id_token` of the authorized user |
@ -227,7 +234,7 @@ Send a client assertion as JWT for us to validate the signature against the regi
#### Required request Parameters
| Parameter | Description |
|------------|-------------------------------------------------------------------------------------------------------------------------|
| ---------- | ----------------------------------------------------------------------------------------------------------------------- |
| grant_type | Must be `urn:ietf:params:oauth:grant-type:jwt-bearer` |
| assertion | JWT built and signed according to [Using JWTs for Authorization Grants](grant-types#using-jwts-as-authorization-grants) |
| scope | [Scopes](scopes) you would like to request from ZITADEL. Scopes are space delimited, e.g. `openid email profile` |
@ -243,7 +250,7 @@ curl --request POST \
#### Successful JWT Profile response {#token-jwt-response}
| Property | Description |
|--------------|---------------------------------------------------------------------------------------|
| ------------ | ------------------------------------------------------------------------------------- |
| access_token | An `access_token` as JWT or opaque token |
| expires_in | Number of second until the expiration of the `access_token` |
| id_token | An `id_token` of the authorized service user |
@ -252,13 +259,13 @@ curl --request POST \
### Refresh Token Grant
To request a new `access_token` without user interaction, you can use the `refresh_token` grant.
To request a new `access_token` without user interaction, you can use the `refresh_token` grant.
See [offline_access Scope](scopes#standard-scopes) for how to request a `refresh_token` in the authorization request.
#### Required request Parameters
| Parameter | Description |
|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| grant_type | Must be `refresh_token` |
| refresh_token | The refresh_token previously issued in the last authorization_code or refresh_token request. |
| scope | [Scopes](scopes) you would like to request from ZITADEL for the new access_token. Must be a subset of the scope originally requested by the corresponding auth request. When omitted, the scopes requested by the original auth request will be reused. Scopes are space delimited, e.g. `openid email profile` |
@ -285,7 +292,7 @@ Send your `client_id` and `client_secret` as Basic Auth Header. Check [Client Se
Send your `client_id` and `client_secret` as parameters in the body:
| Parameter | Description |
|---------------|----------------------------------|
| ------------- | -------------------------------- |
| client_id | client_id of the application |
| client_secret | client_secret of the application |
@ -300,7 +307,7 @@ Send your `client_id` as parameter in the body. No authentication is required.
Send a `client_assertion` as JWT for us to validate the signature against the registered public key.
| Parameter | Description |
|-----------------------|--------------------------------------------------------------------------------------------------------------|
| --------------------- | ------------------------------------------------------------------------------------------------------------ |
| client_assertion | JWT built and signed according to [Using JWTs for Client Authentication](authn-methods#jwt-with-private-key) |
| client_assertion_type | Must be `urn:ietf:params:oauth:client-assertion-type:jwt-bearer` |
@ -310,7 +317,7 @@ Send a `client_assertion` as JWT for us to validate the signature against the re
#### Successful refresh token response {#token-refresh-response}
| Property | Description |
|---------------|---------------------------------------------------------------------------------------|
| ------------- | ------------------------------------------------------------------------------------- |
| access_token | An `access_token` as JWT or opaque token |
| expires_in | Number of second until the expiration of the `access_token` |
| id_token | An `id_token` of the authorized user |
@ -321,7 +328,7 @@ Send a `client_assertion` as JWT for us to validate the signature against the re
### Error response
| error_type | Possible reason |
|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| invalid_request | The request is missing a required parameter, includes an unsupported parameter value (other than grant type), repeats a parameter, includes multiple credentials, utilizes more than one mechanism for authenticating the client, or is otherwise malformed. |
| invalid_scope | The requested scope is invalid, unknown, malformed, or exceeds the scope granted by the resource owner. |
| unauthorized_client | The authenticated client is not authorized to use this authorization grant type. |
@ -338,7 +345,7 @@ This endpoint enables clients to validate an `acccess_token`, either opaque or J
this endpoint will check if the token is not revoked (by client or logout).
| Parameter | Description |
|-----------|-----------------|
| --------- | --------------- |
| token | An access token |
Depending on your authorization method you will have to provide additional parameters or headers:
@ -370,7 +377,7 @@ curl --request POST \
Send a `client_assertion` as JWT for us to validate the signature against the registered public key.
| Parameter | Description |
|-----------------------|-------------------------------------------------------------------------------------------------------------|
| --------------------- | ----------------------------------------------------------------------------------------------------------- |
| client_assertion | JWT built and signed according to [Using JWTs for Client Authentication](authn-methods#client-secret-basic) |
| client_assertion_type | must be `urn:ietf:params:oauth:client-assertion-type:jwt-bearer` |
@ -388,25 +395,25 @@ curl --request POST \
### Successful introspection response {#introspect-response}
Upon successful authorization of the client a response with the boolean `active` is returned, indicating if the provided token
Upon successful authorization of the client a response with the boolean `active` is returned, indicating if the provided token
is active and the requesting client is part of the token audience.
If `active` is **true**, further information will be provided:
| Property | Description |
|------------|------------------------------------------------------------------------|
| aud | The audience of the token |
| client_id | The client_id of the application the token was issued to |
| exp | Time the token expires (as unix time) |
| iat | Time of the token was issued at (as unix time) |
| iss | Issuer of the token |
| jti | Unique id of the token |
| nbf | Time the token must not be used before (as unix time) |
| scope | Space delimited list of scopes granted to the token |
| token_type | Type of the inspected token. Value is always `Bearer` |
| username | ZITADEL's login name of the user. Consist of `username@primarydomain` |
| Property | Description |
| ---------- | --------------------------------------------------------------------- |
| aud | The audience of the token |
| client_id | The client_id of the application the token was issued to |
| exp | Time the token expires (as unix time) |
| iat | Time of the token was issued at (as unix time) |
| iss | Issuer of the token |
| jti | Unique id of the token |
| nbf | Time the token must not be used before (as unix time) |
| scope | Space delimited list of scopes granted to the token |
| token_type | Type of the inspected token. Value is always `Bearer` |
| username | ZITADEL's login name of the user. Consist of `username@primarydomain` |
Additionally and depending on the granted scopes, information about the authorized user is provided.
Additionally and depending on the granted scopes, information about the authorized user is provided.
Check the [Claims](claims) page if a specific claims might be returned and for detailed description.
### Error response {#introspect-error-response}
@ -420,6 +427,7 @@ If the authorization fails, an HTTP 401 with `invalid_client` will be returned.
This endpoint will return information about the authorized user.
Send the `access_token` of the **user** (not the client) as Bearer Token in the `authorization` header:
```BASH
curl --request GET \
--url {your_domain}/oidc/v1/userinfo
@ -446,9 +454,8 @@ If you revoke an `access_token` only the specific token will be revoked. When re
the corresponding `access_token` will be revoked as well.
:::
| Parameter | Description |
|-----------|----------------------------------|
| --------- | -------------------------------- |
| token | An access token or refresh token |
Depending on your authorization method you will have to provide additional parameters or headers:
@ -473,7 +480,7 @@ Send your `client_id` and `client_secret` as Basic Auth Header. Check [Client Se
Send your `client_id` and `client_secret` as parameters in the body:
| Parameter | Description |
|---------------|----------------------------------|
| ------------- | -------------------------------- |
| client_id | client_id of the application |
| client_secret | client_secret of the application |
@ -483,7 +490,7 @@ Send your `client_id` and `client_secret` as parameters in the body:
Send your `client_id` as parameters in the body:
| Parameter | Description |
|-----------|------------------------------|
| --------- | ---------------------------- |
| client_id | client_id of the application |
</TabItem>
@ -492,7 +499,7 @@ Send your `client_id` as parameters in the body:
Send a `client_assertion` as JWT for ZITADEL to verify the signature against the registered public key.
| Parameter | Description |
|-----------------------|---------------------------------------------------------------------------------------------------------------|
| --------------------- | ------------------------------------------------------------------------------------------------------------- |
| client_assertion | JWT created and signed according to [Using JWTs for Client Authentication](authn-methods#client-secret-basic) |
| client_assertion_type | must be `urn:ietf:params:oauth:client-assertion-type:jwt-bearer` |
@ -514,10 +521,10 @@ curl --request POST \
The endpoint has to be opened in the user agent (browser) to terminate the user sessions.
No parameters are needed apart from the user agent cookie, but you can provide the following to customize the behaviour:
No parameters are needed apart from the user agent cookie, but you can provide the following to customize the behaviour:
| Parameter | Description |
|--------------------------|----------------------------------------------------------------------------------------------------------------------------------|
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| id_token_hint | the id_token that was previously issued to the client |
| client_id | client_id of the application |
| post_logout_redirect_uri | Callback uri of the logout where the user (agent) will be redirected to. Must match exactly one of the preregistered in Console. |

View File

@ -166,12 +166,12 @@ Our Android and iOS Application opens ZITADEL's login within a custom tab, on We
If everything works out correctly, your applications should look like this:
<div style={{display: 'grid', 'grid-column-gap': '1rem', 'grid-template-columns': '1fr 1fr', 'max-width': '500px', 'margin': '0 auto'}}>
<div style={{display: 'grid', 'gridColumnGap': '1rem', 'gridTemplateColumns': '1fr 1fr', 'maxWidth': '500px', 'margin': '0 auto'}}>
<img src="/img/flutter/not-authed.png" alt="Unauthenticated" height="500px" />
<img src="/img/flutter/authed.png" alt="Flutter Authenticated" height="500px" />
</div>
<div style={{display: 'grid', 'grid-column-gap': '1rem', 'grid-template-columns': '1fr 1fr', 'max-width': '800px', 'margin': '0 auto'}}>
<div style={{display: 'grid', 'gridColumnGap': '1rem', 'gridTemplateColumns': '1fr 1fr', 'maxWidth': '800px', 'margin': '0 auto'}}>
<img src="/img/flutter/web-not-authed.png" alt="Unauthenticated" height="500px" />
<img src="/img/flutter/web-authed.png" alt="Flutter Authenticated" height="500px" />
</div>

View File

@ -21,16 +21,7 @@ the authentication process. The latter is used to bind the client session with t
You don't need any additional parameter for this request. We're identifying the app by the `client_id` parameter.
So your request might look like this (linebreaks and whitespace for display reasons):
```curl
curl --request GET \
--url '{your-domain}/oauth/v2/authorize
?client_id=${client_id}
&redirect_uri=${redirect_uri}
&response_type=code
&scope=openid%20email%20profile'
```
Try out the request in our [OIDC Authentication Request Playground](/docs/apis/openidoauth/authrequest?auth_method=Client%20Secret%20Basic).
### Additional parameters and customization

View File

@ -23,14 +23,7 @@ You don't need any additional parameter for this request. We're identifying the
So your request might look like this (linebreaks and whitespace for display reasons):
```curl
curl --request GET \
--url '{your-domain}/oauth/v2/authorize
?client_id=${client_id}
&redirect_uri=${redirect_uri}
&response_type=code
&scope=openid%20email%20profile'
```
Try out the request in our [OIDC Authentication Request Playground](/docs/apis/openidoauth/authrequest?auth_method=Client%20Secret%20Basic).
### Additional parameters and customization

View File

@ -29,18 +29,7 @@ the hash as well and to verify it's correct. In order to do so you're required t
For example for `random-string` the code_challenge would be `9az09PjcfuENS7oDK7jUd2xAWRb-B3N7Sr3kDoWECOY`
The request would finally look like (linebreaks and whitespace for display reasons):
```curl
curl --request GET \
--url '{your-domain}/oauth/v2/authorize
?client_id=${client_id}
&redirect_uri=${redirect_uri}
&response_type=code
&scope=openid%20email%20profile
&code_challenge=${code_challenge}
&code_challenge_method=S256'
```
Try out the request in our [OIDC Authentication Request Playground](/docs/apis/openidoauth/authrequest).
### Additional parameters and customization

View File

@ -2,7 +2,8 @@
title: Recommended authorization flows
---
<table class="table-wrapper">
<table className="table-wrapper">
<tbody>
<tr>
<td>Description</td>
<td>Learn about the different authentication flows and which flow we recommend you should use for your application.</td>
@ -24,9 +25,9 @@ title: Recommended authorization flows
Basic knowledge about federated identities
</td>
</tr>
</tbody>
</table>
## Introduction
Before we get into setting up our first application within ZITADEL, we need to go through some basics on how to obtain an authorization with OpenID Connect 1.x and OAuth 2.x.
@ -43,21 +44,22 @@ Although Federated Identities are not a new concept ([RFC 6749](https://tools.ie
The aforementioned RFC provides us with some [problems and limitations](https://tools.ietf.org/html/rfc6749#section-1) of the client-server authentication, where a client requests a protected resource on the server by authenticating with the users credentials:
* Applications need to store users credentials (eg, password) for future use; compromise of any application results in compromise of the end-users credentials
* Servers are required to support password authentication
* Without means of limiting scope when providing the users credentials, the application gains overly broad access to protected resources
* Users cannot revoke access for a single application, but only for all by changing credentials
- Applications need to store users credentials (eg, password) for future use; compromise of any application results in compromise of the end-users credentials
- Servers are required to support password authentication
- Without means of limiting scope when providing the users credentials, the application gains overly broad access to protected resources
- Users cannot revoke access for a single application, but only for all by changing credentials
So what do we want to achieve with delegated authentication?
* Instead of implementing authentication on each server and trusting each server
* Users only **authenticate** with a trusted server (ie. ZITADEL), that validates the users identity through a challenge (eg, multiple authentication factors) and issues an **ID token** (OpenID Connect 1.x)
* Applications have means of **validating the integrity** of presented access and ID tokens
- Instead of implementing authentication on each server and trusting each server
* Instead of sending around the users credentials
* Clients may access protected resources with an **access token** that is only valid for specific scope and limited lifetime (OAuth 2.x)
* Users have to **authorize** applications to access certain [**scopes**](../../apis/openidoauth/scopes) (eg, email address or custom roles). Applications can request [**claims**](../../apis/openidoauth/claims) (key:value pairs, eg email address) for the authorized scopes with the access token or ID token from ZITADEL
* Access tokens are bearer tokens, meaning that possession of the token provides access to a resource. But the tokens expire frequently and the application must request a new access token via **refresh token** or the user must reauthenticate
- Users only **authenticate** with a trusted server (ie. ZITADEL), that validates the users identity through a challenge (eg, multiple authentication factors) and issues an **ID token** (OpenID Connect 1.x)
- Applications have means of **validating the integrity** of presented access and ID tokens
- Instead of sending around the users credentials
- Clients may access protected resources with an **access token** that is only valid for specific scope and limited lifetime (OAuth 2.x)
- Users have to **authorize** applications to access certain [**scopes**](../../apis/openidoauth/scopes) (eg, email address or custom roles). Applications can request [**claims**](../../apis/openidoauth/claims) (key:value pairs, eg email address) for the authorized scopes with the access token or ID token from ZITADEL
- Access tokens are bearer tokens, meaning that possession of the token provides access to a resource. But the tokens expire frequently and the application must request a new access token via **refresh token** or the user must reauthenticate
![Overview federated identities](/img/guides/consulting_federated_identities_basics.png)
@ -74,19 +76,20 @@ As mentioned in the beginning of this module, there are two main determinants fo
OAuth 2.x defines two [client types](https://tools.ietf.org/html/rfc6749#section-2.1) based on their ability to maintain the confidentiality of their client credentials:
* Confidential: Clients capable of maintaining the confidentiality of their credentials (e.g., client implemented on a secure server with restricted access to the client credentials), or capable of secure client authentication using other means.
* Public: Clients incapable of maintaining the confidentiality of their credentials (e.g., clients executing on the device used by the resource owner, such as an installed native application or a web browser-based application), and incapable of secure client authentication via any other means.
- Confidential: Clients capable of maintaining the confidentiality of their credentials (e.g., client implemented on a secure server with restricted access to the client credentials), or capable of secure client authentication using other means.
- Public: Clients incapable of maintaining the confidentiality of their credentials (e.g., clients executing on the device used by the resource owner, such as an installed native application or a web browser-based application), and incapable of secure client authentication via any other means.
The following table gives you a brief overview of different client profiles.
<table class="table-wrapper">
<table className="table-wrapper">
<tbody>
<tr>
<th>Confidentiality of client credentials</th>
<th>Client profile</th>
<th>Examples of clients</th>
</tr>
<tr>
<td rowspan="2">Public</td>
<td rowSpan="2">Public</td>
<td>User-Agent</td>
<td>Single-page web applications (SPA), generally JavaScript executed in Browser</td>
</tr>
@ -95,7 +98,7 @@ The following table gives you a brief overview of different client profiles.
<td>Native, Mobile, or Desktop applications</td>
</tr>
<tr>
<td rowspan="2">Confidential</td>
<td rowSpan="2">Confidential</td>
<td>Web</td>
<td>Server-side web applications such as java, .net, …</td>
</tr>
@ -103,6 +106,7 @@ The following table gives you a brief overview of different client profiles.
<td>Machine-to-Machine</td>
<td>APIs, generally services without direct user-interaction at the authorization server</td>
</tr>
</tbody>
</table>
## Our recommended authorization flows
@ -111,7 +115,7 @@ We recommend using the flow **“Authorization Code with Proof Key of Code Excha
If you dont have any technical limitations, you should favor the flow Authorization Code with PKCE over other methods. The PKCE part makes the flow resistant against authorization code interception attack as described well in RFC7636.
*So what about APIs?*
_So what about APIs?_
We recommend using **“JWT bearer token with private key”** ([RFC7523](https://tools.ietf.org/html/rfc7523)) for Machine-to-Machine clients.
@ -125,13 +129,13 @@ In case you need alternative flows and their advantages and drawbacks, there wil
## Summary (3)
* Federated Identities solve key problems and challenges with traditional server-client architecture
* Use “Authorization Code with Proof Key of Code Exchange (PKCE)” for User-Agent, Native, and Web clients
* “JWT bearer token with private key” for Machine-to-Machine clients
* There are alternative flows and fallback strategies supported by ZITADEL, if these flows are technically not possible
- Federated Identities solve key problems and challenges with traditional server-client architecture
- Use “Authorization Code with Proof Key of Code Exchange (PKCE)” for User-Agent, Native, and Web clients
- “JWT bearer token with private key” for Machine-to-Machine clients
- There are alternative flows and fallback strategies supported by ZITADEL, if these flows are technically not possible
### Where to go from here
* Applications
* Service Accounts
* Alternative authentication flows (aka. "The Zoo")
- Applications
- Service Accounts
- Alternative authentication flows (aka. "The Zoo")

View File

@ -9,7 +9,7 @@ After users register using an external identity provider, the action assigns the
Before you start, make sure you have everything set up correctly.
- You need to be at least a ZITADEL *ORG_OWNER*
- You need to be at least a ZITADEL _ORG_OWNER_
- Your ZITADEL organization needs to have the actions feature enabled. <!-- TODO: How to enable it for SaaS ZITADEL? -->
- [Your ZITADEL organization needs to have at least one external identity provider enabled](../../integrate/identity-brokering)
- [You need to have at least one role configured for a project](../console/projects)
@ -24,12 +24,11 @@ Before you start, make sure you have everything set up correctly.
## Create the action
1. Select the **Actions** navigation item.
1. In the **Actions <i class="las la-code"></i>** section, select the **+ New** button.
1. In the **Actions <i className="las la-code"></i>** section, select the **+ New** button.
1. Give the new action the name `addGrant`.
1. Paste this snippet into the multiline textfield.
1. Replace the snippets placeholders and select **Save**.
```js reference
https://github.com/zitadel/actions/blob/main/examples/add_user_grant.js
```
@ -38,11 +37,11 @@ https://github.com/zitadel/actions/blob/main/examples/add_user_grant.js
Now, make the action hook into the [external authentication flow](../../../apis/actions/register-flow#external-authentication).
1. In the **Flows <i class="las la-exchange-alt"></i>** section, select the **+ New** button.
2. Select the **Flow Type** *External Authentication*.
3. Select the **Trigger Type** *Post Creation*.
4. In the **Actions** dropdown, check *addGrant*.
5. Select the **Save** button.
1. In the **Flows <i className="las la-exchange-alt"></i>** section, select the **+ New** button.
1. Select the **Flow Type** _External Authentication_.
1. Select the **Trigger Type** _Post Creation_.
1. In the **Actions** dropdown, check _addGrant_.
1. Select the **Save** button.
<!-- TODO: ## Test if your action works -->
@ -51,4 +50,4 @@ New users automatically are assiged a role now if they register by authenticatin
## What's next?
- [Read more about the concepts around actions](../../../concepts/features/actions)
- [Read more about all the options you have with actions](../../../apis/actions/introduction)
- [Read more about all the options you have with actions](../../../apis/actions/introduction)

View File

@ -43,22 +43,10 @@ If you like to trigger your settings for your applications you have different po
### 1. Primary Domain Scope
Send a [primary domain scope](../../../apis/openidoauth/scopes) with your [authorization request](../../integrate/login-users#auth-request) to trigger your organization.
Send a [reserved scope](../../../apis/openidoauth/scopes) with your [authorization request](../../integrate/login-users#auth-request) to trigger your organization.
The primary domain scope will restrict the login to your organization, so only users of your own organization will be able to login.
See the following link as an example. Users will be able to register and login to the organization that verified the @caos.ch domain only.
```
https://{your_domain.zitadel.cloud}/oauth/v2/authorize?client_id=69234247558357051%40zitadel&scope=openid%20profile%20urn%3Azitadel%3Aiam%3Aorg%3Adomain%3Aprimary%3Acaos.ch&redirect_uri=https%3A%2F%2Fconsole.zitadel.cloud%2Fauth%2Fcallback&state=testd&response_type=code&nonce=test&code_challenge=UY30LKMy4bZFwF7Oyk6BpJemzVblLRf0qmFT8rskUW0
```
:::info
Make sure to replace the domain `caos.ch` with your own domain to trigger the correct branding.
:::
:::caution
This example uses the ZITADEL Cloud Application for demonstration. You need to create your own auth request with your applications parameters. Please see the docs to construct an [Auth Request]../integrate/login-users#auth-request).
:::
You can use our [OpenID Authentication Request Playground](/docs/apis/openidoauth/authrequest) to learn more about how to trigger an [organization's policies and branding](/docs/apis/openidoauth/authrequest#organization-policies-and-branding).
### 2. Setting on your Project

View File

@ -107,33 +107,7 @@ Export the result to the environment variable `BASIC_AUTH`.
### Create Auth Request
You need to create a valid auth request, including the reserved scope `urn:zitadel:iam:user:metadata`. Please refer to our API documentation for more information about [reserved scopes](../../../apis/openidoauth/scopes#reserved-scopes).
<Tabs>
<TabItem value="default" label="Default" default>
```bash
echo "${ZITADEL_DOMAIN}/oauth/v2/authorize?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code&scope=openid email profile urn:zitadel:iam:user:metadata"
```
</TabItem>
<TabItem value="macos" label="MacOS">
```zsh
open "${ZITADEL_DOMAIN}/oauth/v2/authorize?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code&scope=openid email profile urn:zitadel:iam:user:metadata"
```
</TabItem>
<TabItem value="WSL" label="WSL">
```bash
wslview "${ZITADEL_DOMAIN}/oauth/v2/authorize?client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI}&response_type=code&scope=openid email profile urn:zitadel:iam:user:metadata"
```
</TabItem>
</Tabs>
You need to create a valid auth request, including the reserved scope `urn:zitadel:iam:user:metadata`. Please refer to our API documentation for more information about [reserved scopes](../../../apis/openidoauth/scopes#reserved-scopes) or try it out in our [OIDC Authrequest Playground](/docs/apis/openidoauth/authrequest?scope=openid%20email%20profile%20urn%3Azitadel%3Aiam%3Auser%3Ametadata).
Login with the user to which you have added the metadata. After the login you will be redirected.

View File

@ -18,7 +18,7 @@ This guide attempts to explain real-world implementations and break them down in
<ListElement
link="./b2c"
iconClasses="las la-paragraph"
roundClasses="rounded rounded-split"
roundClasses="custom-rounded rounded-split"
label="B2C"
title="Business to Consumer"
description="Organizations with your SDLC, Domains, Authentication, Hosted Login"
@ -26,7 +26,7 @@ This guide attempts to explain real-world implementations and break them down in
<ListElement
link="./b2b"
iconClasses="las la-paragraph"
roundClasses="rounded rounded-split"
roundClasses="custom-rounded rounded-split"
label="B2B"
title="Business to Business"
description="Planning considerations, B2B Sample Case"

View File

@ -19,10 +19,17 @@ module.exports = {
},
],
customFields: {
description: "Documentation for ZITADEL - The best of Auth0 and Keycloak combined. Built for the serverless era.",
description:
"Documentation for ZITADEL - The best of Auth0 and Keycloak combined. Built for the serverless era.",
},
themeConfig: {
metadata: [{name: 'keywords', content: 'zitadel, documentation, jwt, saml, oauth2, authentication, serverless, login, auth, authorization, sso, openid-connect, oidc, mfa, 2fa, passkeys, fido2, docker'}],
metadata: [
{
name: "keywords",
content:
"zitadel, documentation, jwt, saml, oauth2, authentication, serverless, login, auth, authorization, sso, openid-connect, oidc, mfa, 2fa, passkeys, fido2, docker",
},
],
zoom: {
selector: ".markdown :not(em) > img",
background: {
@ -77,19 +84,22 @@ module.exports = {
position: "left",
},
{
href: "https://github.com/zitadel/zitadel",
label: "GitHub",
type: "html",
position: "right",
value:
'<a href="https://github.com/zitadel/zitadel/discussions" style="text-decoration: none; width: 20px; height: 24px; display: flex"><i class="las la-comments"></i></a>',
},
{
href: "https://zitadel.com/chat",
label: "Chat",
type: "html",
position: "right",
value:
'<a href="https://github.com/zitadel/zitadel" style="text-decoration: none; width: 20px; height: 24px; display: flex"><i class="lab la-github"></i></a>',
},
{
label: "Discussions",
type: "html",
position: "right",
href: "https://github.com/zitadel/zitadel/discussions",
value:
'<a href="https://zitadel.com/chat" style="text-decoration: none; width: 20px; height: 24px; display: flex; margin: 0 .5rem 0 0"><i class="lab la-discord"></i></a>',
},
],
},
@ -193,6 +203,19 @@ module.exports = {
},
],
],
plugins: [require.resolve("docusaurus-plugin-image-zoom")],
plugins: [
require.resolve("docusaurus-plugin-image-zoom"),
async function myPlugin(context, options) {
return {
name: "docusaurus-tailwindcss",
configurePostCss(postcssOptions) {
// Appends TailwindCSS and AutoPrefixer.
postcssOptions.plugins.push(require("tailwindcss"));
postcssOptions.plugins.push(require("autoprefixer"));
return postcssOptions;
},
};
},
],
themes: ["@saucelabs/theme-github-codeblock"],
};

View File

@ -47,6 +47,8 @@
"@docusaurus/theme-classic": "^2.1.0",
"@docusaurus/theme-search-algolia": "^2.1.0",
"@docusaurus/types": "^2.1.0",
"@headlessui/react": "^1.7.4",
"@heroicons/react": "^2.0.13",
"@jridgewell/resolve-uri": "3.0.7",
"@jridgewell/set-array": "1.1.1",
"@jridgewell/trace-mapping": "0.3.11",
@ -63,16 +65,17 @@
"@types/react-router-config": "5.0.6",
"@types/react-router-dom": "5.3.3",
"@types/ws": "8.5.3",
"autoprefixer": "10.4.7",
"autoprefixer": "^10.4.13",
"axios": "0.25.0",
"babel-loader": "8.2.5",
"body-parser": "1.20.0",
"bonjour-service": "1.0.12",
"boxen": "6.2.1",
"buffer": "^6.0.3",
"clean-css": "5.3.0",
"cli-boxes": "3.0.0",
"cli-table3": "0.6.2",
"clsx": "^1.1.1",
"clsx": "^1.2.1",
"cookie": "0.5.0",
"copy-webpack-plugin": "10.2.4",
"core-js": "3.22.5",
@ -106,6 +109,7 @@
"node-forge": "1.3.1",
"object-inspect": "1.12.0",
"plugin-image-zoom": "ataft/plugin-image-zoom",
"postcss": "^8.4.19",
"postcss-calc": "8.2.4",
"postcss-colormin": "5.3.0",
"postcss-convert-values": "5.1.0",
@ -179,5 +183,8 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"tailwindcss": "^3.2.4"
}
}

View File

@ -236,6 +236,7 @@ module.exports = {
collapsed: false,
items: [
"apis/openidoauth/endpoints",
"apis/openidoauth/authrequest",
"apis/openidoauth/scopes",
"apis/openidoauth/claims",
"apis/openidoauth/authn-methods",

View File

@ -1,34 +1,32 @@
import React from 'react';
import React from "react";
import styles from '../css/apicard.module.css';
import styles from "../css/apicard.module.css";
export function ApiCard({ title, type, label, children}) {
let style = styles.apiauth;
export function ApiCard({ type, children }) {
let classes = "";
switch (type) {
case 'AUTH':
style = styles.apiauth;
case "AUTH":
classes = "bg-green-500/10 dark:bg-green-500/20";
break;
case 'MGMT':
style = styles.apimgmt;
case "MGMT":
classes = "bg-blue-500/10 dark:bg-blue-500/20";
break;
case 'ADMIN':
style = styles.apiadmin;
case "ADMIN":
classes = "bg-red-500/10 dark:bg-red-500/20";
break;
case 'SYSTEM':
style = styles.apisystem;
case "SYSTEM":
classes = "bg-yellow-500/10 dark:bg-yellow-500/20";
break;
case "ASSET":
classes = "bg-black/10 dark:bg-black/20";
break;
case 'ASSET':
style = styles.apiasset;
break;
}
return (
<div className={`${styles.apicard} ${style} `}>
{/* {title && <h2 className={styles.apicard.title}>{title}</h2>} */}
{/* <p className={styles.apicard.description}>
</p> */}
<div
className={`${styles.apicard} flex mb-4 flex-row p-4 rounded-lg ${classes} `}
>
{children}
</div>
)
);
}

View File

@ -0,0 +1,594 @@
import React, { Fragment, useContext, useEffect, useState } from "react";
import { AuthRequestContext } from "../utils/authrequest";
import { Listbox } from "@headlessui/react";
import { Transition } from "@headlessui/react";
import { ChevronUpDownIcon, CheckIcon } from "@heroicons/react/24/solid";
import clsx from "clsx";
import { Buffer } from "buffer";
export function SetAuthRequest() {
const {
instance: [instance, setInstance],
clientId: [clientId, setClientId],
redirectUri: [redirectUri, setRedirectUri],
responseType: [responseType, setResponseType],
scope: [scope, setScope],
prompt: [prompt, setPrompt],
authMethod: [authMethod, setAuthMethod],
codeVerifier: [codeVerifier, setCodeVerifier],
codeChallenge: [codeChallenge, setCodeChallenge],
loginHint: [loginHint, setLoginHint],
idTokenHint: [idTokenHint, setIdTokenHint],
organizationId: [organizationId, setOrganizationId],
} = useContext(AuthRequestContext);
const inputClasses = (error) =>
clsx({
"w-full sm:text-sm h-10 mb-2px rounded-md p-2 bg-input-light-background dark:bg-input-dark-background transition-colors duration-300": true,
"border border-solid border-input-light-border dark:border-input-dark-border hover:border-black hover:dark:border-white focus:border-primary-light-500 focus:dark:border-primary-dark-500": true,
"focus:outline-none focus:ring-0 text-base text-black dark:text-white placeholder:italic placeholder-gray-700 dark:placeholder-gray-700": true,
"border border-warn-light-500 dark:border-warn-dark-500 hover:border-warn-light-500 hover:dark:border-warn-dark-500 focus:border-warn-light-500 focus:dark:border-warn-dark-500":
error,
});
const labelClasses = "text-sm";
const hintClasses = "mt-1 text-xs text-black/50 dark:text-white/50";
const allResponseTypes = ["code", "id_token", "id_token token"];
const allPrompts = ["", "login", "select_account", "create"];
const allAuthMethods = ["(none) PKCE", "Client Secret Basic"];
const CodeSnipped = ({ cname, children }) => {
return <span className={cname}>{children}</span>;
};
const allScopes = [
"openid",
"email",
"profile",
"address",
"offline_access",
"urn:zitadel:iam:org:project:id:zitadel:aud",
"urn:zitadel:iam:user:metadata",
`urn:zitadel:iam:org:id:${
organizationId ? organizationId : "[organizationId]"
}`,
];
const [scopeState, setScopeState] = useState(
[true, true, true, false, false, false, false, false]
// new Array(allScopes.length).fill(false)
);
function toggleScope(position, forceChecked = false) {
const updatedCheckedState = scopeState.map((item, index) =>
index === position ? !item : item
);
if (forceChecked) {
updatedCheckedState[position] = true;
}
setScopeState(updatedCheckedState);
setScope(
updatedCheckedState
.map((checked, i) => (checked ? allScopes[i] : ""))
.filter((s) => !!s)
.join(" ")
);
}
// Encoding functions for code_challenge
async function string_to_sha256(message) {
// encode as UTF-8
const msgBuffer = new TextEncoder().encode(message);
// hash the message
const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer);
// return ArrayBuffer
return hashBuffer;
}
async function encodeCodeChallenge(codeChallenge) {
let arrayBuffer = await string_to_sha256(codeChallenge);
let buffer = Buffer.from(arrayBuffer);
let base64 = buffer.toString("base64");
let base54url = base64_to_base64url(base64);
return base54url;
}
var base64_to_base64url = function (input) {
input = input.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
return input;
};
useEffect(async () => {
setCodeChallenge(await encodeCodeChallenge(codeVerifier));
}, [codeVerifier]);
useEffect(() => {
const newScopeState = allScopes.map((s) => scope.includes(s));
if (scopeState !== newScopeState) {
setScopeState(newScopeState);
}
}, [scope]);
return (
<div className="bg-white/5 rounded-md p-6 shadow">
<h5 className="text-lg mt-0 mb-4 font-semibold">Your Domain</h5>
<div className="flex flex-col">
<label className={`${labelClasses} text-yellow-500`}>
Instance Domain
</label>
<input
className={inputClasses(false)}
id="instance"
value={instance}
onChange={(event) => {
const value = event.target.value;
setInstance(value);
}}
/>
<span className={hintClasses}>
The domain of your zitadel instance.
</span>
</div>
<h5 className="text-lg mt-6 mb-2 font-semibold">Required Parameters</h5>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div className="flex flex-col">
<label className={`${labelClasses} text-green-500`}>Client ID</label>
<input
className={inputClasses(false)}
id="client_id"
value={clientId}
onChange={(event) => {
const value = event.target.value;
setClientId(value);
}}
/>
<span className={hintClasses}>
This is the resource id of an application. It's the application
where you want your users to login.
</span>
</div>
<div className="flex flex-col">
<label className={`${labelClasses} text-blue-500`}>
Redirect URI
</label>
<input
className={inputClasses(false)}
id="redirect_uri"
value={redirectUri}
onChange={(event) => {
const value = event.target.value;
setRedirectUri(value);
}}
/>
<span className={hintClasses}>
Must be one of the pre-configured redirect uris for your
application.
</span>
</div>
<div className="flex flex-col">
<label className={`${labelClasses} text-orange-500`}>
ResponseType
</label>
<Listbox value={responseType} onChange={setResponseType}>
<div className="relative">
<Listbox.Button className="transition-colors duration-300 text-black dark:text-white h-10 relative w-full cursor-default rounded-md bg-white dark:bg-input-dark-background py-2 pl-3 pr-10 text-left focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm border border-solid border-input-light-border dark:border-input-dark-border hover:border-black hover:dark:border-white focus:border-primary-light-500 focus:dark:border-primary-dark-500">
<span className="block truncate">{responseType}</span>
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<ChevronUpDownIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</span>
</Listbox.Button>
<span className={`${hintClasses} flex`}>
Determines whether a code, id_token token or just id_token will
be returned. Most use cases will need code.
</span>
<Transition
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="pl-0 list-none z-10 top-10 absolute mt-1 max-h-60 w-full overflow-auto rounded-md bg-white dark:bg-background-dark-300 text-black dark:text-white py-1 text-base ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
{allResponseTypes.map((type, typeIdx) => (
<Listbox.Option
key={typeIdx}
className={({ active }) =>
`relative cursor-default select-none py-2 pl-10 pr-4 ${
active ? "bg-black/20 dark:bg-white/20" : ""
}`
}
value={type}
>
{({ selected }) => (
<>
<span
className={`block truncate ${
selected ? "font-medium" : "font-normal"
}`}
>
{type}
</span>
{selected ? (
<span className="absolute inset-y-0 left-0 flex items-center pl-3 text-orange-500 dark:text-orange-400">
<CheckIcon
className="h-5 w-5"
aria-hidden="true"
/>
</span>
) : null}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</div>
</Listbox>
</div>
</div>
<div className="grid grid-cols-2 md:grid-cols-2 lg:grid-cols-3 gap-4 mt-6">
<div className="flex flex-col">
<label className={`${labelClasses} text-teal-600`}>
Authentication method
</label>
<Listbox value={authMethod} onChange={setAuthMethod}>
<div className="relative">
<Listbox.Button className="transition-colors duration-300 text-black dark:text-white h-10 relative w-full cursor-default rounded-md bg-white dark:bg-input-dark-background py-2 pl-3 pr-10 text-left focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm border border-solid border-input-light-border dark:border-input-dark-border hover:border-black hover:dark:border-white focus:border-primary-light-500 focus:dark:border-primary-dark-500">
<span className="block truncate">{authMethod}</span>
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<ChevronUpDownIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</span>
</Listbox.Button>
<span className={`${hintClasses} flex`}>
Authentication method
</span>
<Transition
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="pl-0 list-none z-10 absolute top-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white dark:bg-background-dark-300 text-black dark:text-white py-1 text-base ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
{allAuthMethods.map((type, typeIdx) => (
<Listbox.Option
key={typeIdx}
className={({ active }) =>
`h-10 relative cursor-default select-none py-2 pl-10 pr-4 ${
active ? "bg-black/20 dark:bg-white/20" : ""
}`
}
value={type}
>
{({ selected }) => (
<>
<span
className={`block truncate ${
selected ? "font-medium" : "font-normal"
}`}
>
{type}
</span>
{selected ? (
<span className="absolute inset-y-0 left-0 flex items-center pl-3 text-cyan-500 dark:text-cyan-400">
<CheckIcon
className="h-5 w-5"
aria-hidden="true"
/>
</span>
) : null}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</div>
</Listbox>
</div>
{authMethod === "(none) PKCE" && (
<div className="flex flex-col">
<label className={`${labelClasses} text-teal-600`}>
Code Verifier
</label>
<input
className={inputClasses(false)}
id="code_verifier"
value={codeVerifier}
onChange={(event) => {
const value = event.target.value;
setCodeVerifier(value);
}}
/>
<span className={hintClasses}>
<span className="text-teal-600">Authentication method</span> PKCE
requires a random string used to generate a{" "}
<code>code_challenge</code>
</span>
</div>
)}
</div>
<h5 className="text-lg mt-6 mb-2 font-semibold">Additional Parameters</h5>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
<div>
<div className="flex flex-col">
<label className={`${labelClasses} text-cyan-500`}>Prompt</label>
<Listbox value={prompt} onChange={setPrompt}>
<div className="relative">
<Listbox.Button className="transition-colors duration-300 text-black dark:text-white h-10 relative w-full cursor-default rounded-md bg-white dark:bg-input-dark-background py-2 pl-3 pr-10 text-left focus:outline-none focus-visible:border-indigo-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-orange-300 sm:text-sm border border-solid border-input-light-border dark:border-input-dark-border hover:border-black hover:dark:border-white focus:border-primary-light-500 focus:dark:border-primary-dark-500">
<span className="block truncate">{prompt}</span>
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<ChevronUpDownIcon
className="h-5 w-5 text-gray-400"
aria-hidden="true"
/>
</span>
</Listbox.Button>
<span className={`${hintClasses} flex`}>
Define how the user should be prompted on login and register.
</span>
<Transition
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="pl-0 list-none z-10 absolute top-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-white dark:bg-background-dark-300 text-black dark:text-white py-1 text-base ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
{allPrompts.map((type, typeIdx) => (
<Listbox.Option
key={typeIdx}
className={({ active }) =>
`h-10 relative cursor-default select-none py-2 pl-10 pr-4 ${
active ? "bg-black/20 dark:bg-white/20" : ""
}`
}
value={type}
>
{({ selected }) => (
<>
<span
className={`block truncate ${
selected ? "font-medium" : "font-normal"
}`}
>
{type}
</span>
{selected ? (
<span className="absolute inset-y-0 left-0 flex items-center pl-3 text-cyan-500 dark:text-cyan-400">
<CheckIcon
className="h-5 w-5"
aria-hidden="true"
/>
</span>
) : null}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</div>
</Listbox>
</div>
</div>
{prompt === "select_account" && (
<div className="flex flex-col">
<label className={`${labelClasses} text-rose-500`}>
Login hint
</label>
<input
className={inputClasses(false)}
id="login_hint"
value={loginHint}
onChange={(event) => {
const value = event.target.value;
setLoginHint(value);
}}
/>
<span className={hintClasses}>
This in combination with a{" "}
<span className="text-black dark:text-white">select_account</span>{" "}
<span className="text-cyan-500">prompt</span> the login will
preselect a user.
</span>
</div>
)}
{/* <div className="flex flex-col">
<label className={`${labelClasses} text-blue-500`}>
ID Token hint
</label>
<input
className={inputClasses(false)}
id="id_token_hint"
value={idTokenHint}
onChange={(event) => {
const value = event.target.value;
setIdTokenHint(value);
}}
/>
<span className={hintClasses}>
This in combination with a{" "}
<span className="text-black dark:text-white">select_account</span>{" "}
<span className="text-emerald-500">prompt</span> the login will
preselect a user.
</span>
</div> */}
</div>
<h5 className="text-lg mt-6 mb-2 font-semibold">Scopes</h5>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-4">
<div className="flex flex-col">
<label className={`${labelClasses} text-purple-500`}>
Organization ID
</label>
<input
className={inputClasses(false)}
id="organization_id"
value={organizationId}
onChange={(event) => {
const value = event.target.value;
setOrganizationId(value);
allScopes[7] = `urn:zitadel:iam:org:id:${
value ? value : "[organizationId]"
}`;
toggleScope(8, true);
setScope(
scopeState
.map((checked, i) => (checked ? allScopes[i] : ""))
.filter((s) => !!s)
.join(" ")
);
}}
/>
<span className={hintClasses}>
Enforce organization policies and user membership by requesting the{" "}
<span className="text-purple-500">scope</span>{" "}
<code>urn:zitadel:iam:org:id:{organizationId}</code>
</span>
</div>
</div>
<div className="py-4">
<p className="text-sm mt-0 mb-0 text-purple-500">Scopes</p>
<span className={`${hintClasses} flex mb-2`}>
Request additional information about the user with scopes. The claims
will be returned on the userinfo_endpoint or in the token (when
configured).
</span>
{allScopes.map((scope, scopeIndex) => {
return (
<div key={`scope-${scope}`} className="flex flex-row items-center">
<input
type="checkbox"
id={`scope_${scope}`}
name="scopes"
value={`${scope}`}
checked={scopeState[scopeIndex]}
onChange={() => {
toggleScope(scopeIndex);
}}
/>
<label className="ml-4" htmlFor={`scope_${scope}`}>
{scope}{" "}
{scopeIndex === 8 && scopeState[8] && !organizationId ? (
<strong className="text-red-500">
Organization ID missing!
</strong>
) : null}
</label>
</div>
);
})}
</div>
{/* <h5>Optional Parameters</h5>
<div className={styles.grid}>
<div className={styles.inputwrapper}>
<label className={styles.label}>Id Token Hint</label>
<input
className={styles.input}
id="id_token_hint"
value={idTokenHint}
onChange={(event) => {
const value = event.target.value;
setIdTokenHint(value);
}}
/>
</div>
</div> */}
<h5 className="text-lg mt-6 mb-2 font-semibold">
Your authorization request
</h5>
<div className="rounded-md bg-gray-700 shadow dark:bg-black/10 p-2 flex flex-col items-center">
<code className="text-sm w-full mb-4 bg-transparent border-none">
<span className="text-yellow-500">
{instance.endsWith("/") ? instance : instance + "/"}
</span>
<span className="text-white">oauth/v2/authorize?</span>
<CodeSnipped cname="text-green-500">{`client_id=${encodeURIComponent(
clientId
)}`}</CodeSnipped>
<CodeSnipped cname="text-blue-500">{`&redirect_uri=${encodeURIComponent(
redirectUri
)}`}</CodeSnipped>
<CodeSnipped cname="text-orange-500">
{`&response_type=${encodeURIComponent(responseType)}`}
</CodeSnipped>
<CodeSnipped cname="text-purple-500">{`&scope=${encodeURIComponent(
scope
)}`}</CodeSnipped>
{prompt && (
<CodeSnipped cname="text-cyan-500">{`&prompt=${encodeURIComponent(
prompt
)}`}</CodeSnipped>
)}
{loginHint && prompt === "select_account" && (
<CodeSnipped cname="text-rose-500">{`&login_hint=${encodeURIComponent(
loginHint
)}`}</CodeSnipped>
)}
{authMethod === "(none) PKCE" && (
<CodeSnipped cname="text-teal-600">{`&code_challenge=${encodeURIComponent(
codeChallenge
)}&code_challenge_method=S256`}</CodeSnipped>
)}
</code>
<a
onClick={() => {
window.plausible("OIDC Playground", {
props: { method: "Try it out", pageloc: "Authorize" },
});
}}
target="_blank"
className="mt-2 flex flex-row items-center py-2 px-4 text-white bg-green-500 dark:bg-green-600 hover:dark:bg-green-500 hover:text-white rounded-md hover:no-underline font-semibold text-sm"
href={`${
instance.endsWith("/") ? instance : instance + "/"
}oauth/v2/authorize?client_id=${encodeURIComponent(
clientId
)}&redirect_uri=${encodeURIComponent(
redirectUri
)}&response_type=${encodeURIComponent(
responseType
)}&scope=${encodeURIComponent(scope)}${
prompt ? `&prompt=${encodeURIComponent(prompt)}` : ""
}${
loginHint && prompt === "select_account"
? `&login_hint=${encodeURIComponent(loginHint)}`
: ""
}${
authMethod === "(none) PKCE"
? `&code_challenge=${encodeURIComponent(
codeChallenge
)}&code_challenge_method=S256`
: ""
}`}
>
<span>Try it out</span>
<i className="text-white text-md ml-2 las la-external-link-alt"></i>
</a>
</div>
</div>
);
}

View File

@ -1,11 +1,7 @@
import React from 'react';
import React from "react";
import styles from '../css/column.module.css';
export default function Column({children}) {
return (
<div className={styles.column}>
{children}
</div>
)
}
export default function Column({ children }) {
return (
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2">{children}</div>
);
}

View File

@ -0,0 +1,133 @@
import React, { useContext, useEffect } from "react";
import { EnvironmentContext } from "../utils/environment";
import styles from "../css/environment.module.css";
import Interpolate from "@docusaurus/Interpolate";
import CodeBlock from "@theme/CodeBlock";
export function SetEnvironment() {
const {
instance: [instance, setInstance],
clientId: [clientId, setClientId],
} = useContext(EnvironmentContext);
useEffect(() => {
const params = new URLSearchParams(window.location.search); // id=123
const clientId = params.get("clientId");
const instance = params.get("instance");
const localClientId = localStorage.getItem("clientId");
const localInstance = localStorage.getItem("instance");
setClientId(clientId ?? localClientId ?? "");
setInstance(instance ?? localInstance ?? "");
}, []);
function setAndSaveInstance(value) {
if (instance !== value) {
localStorage.setItem("instance", value);
setInstance(value);
}
}
function setAndSaveClientId(value) {
if (clientId !== value) {
localStorage.setItem("clientId", value);
setClientId(value);
}
}
return (
<div>
<div className={styles.inputwrapper}>
<label className={styles.label}>Your instance domain</label>
<input
className={styles.input}
id="instance"
value={instance}
onChange={(event) => {
const value = event.target.value;
if (value) {
setAndSaveInstance(value);
} else {
localStorage.removeItem("instance");
}
}}
/>
</div>
<br />
<div className={styles.inputwrapper}>
<label className={styles.label}>Client ID</label>
<input
className={styles.input}
id="clientid"
value={clientId}
onChange={(event) => {
const value = event.target.value;
if (value) {
setAndSaveClientId(value);
} else {
localStorage.removeItem("clientId");
}
}}
/>
</div>
</div>
);
}
export function Env({ name }) {
const env = useContext(EnvironmentContext);
const variable = env[name];
return <div>{variable}</div>;
}
export function EnvInterpolate({ children }) {
const {
instance: [instance],
clientId: [clientId],
} = useContext(EnvironmentContext);
return (
<Interpolate
values={{
clientId,
instance,
}}
>
{children}
</Interpolate>
);
}
export function EnvCode({
language,
title,
code,
showLineNumbers = false,
children,
}) {
const {
instance: [instance],
clientId: [clientId],
} = useContext(EnvironmentContext);
return (
<CodeBlock
language={language}
title={title}
showLineNumbers={showLineNumbers}
>
<Interpolate
values={{
clientId,
instance,
}}
>
{children}
</Interpolate>
</CodeBlock>
);
}

View File

@ -1,113 +1,181 @@
import React from 'react';
import React from "react";
import styles from '../css/list.module.css';
import styles from "../css/list.module.css";
export const ICONTYPE = {
START: <div className="rounded rounded-start">
<i className={`las la-play-circle`}></i>
</div>,
TASKS: <div className="rounded rounded-start">
<i className={`las la-tasks`}></i>
</div>,
ARCHITECTURE: <div className="rounded rounded-architecture">
<i className={`las la-sitemap`}></i>
</div>,
INSTANCE: <div className="rounded rounded-instance">
<i className={`las la-industry`}></i>
</div>,
LOGIN: <div className="rounded rounded-login">
<i className={`las la-sign-in-alt`}></i>
</div>,
PRIVATELABELING: <div className="rounded rounded-privatelabel">
<i className={`las la-swatchbook`}></i>
</div>,
TEXTS: <div className="rounded rounded-texts">
<i className={`las la-paragraph`}></i>
</div>,
POLICY: <div className="rounded rounded-policy">
<i className={`las la-file-contract`}></i>
</div>,
SERVICE: <div className="rounded rounded-service">
<i className={`las la-concierge-bell`}></i>
</div>,
STORAGE: <div className="rounded rounded-storage">
<i className={`las la-database`}></i>
</div>,
FOLDER: <div className="rounded rounded-storage">
<i className={`las la-folder`}></i>
</div>,
FILE: <div className="rounded rounded-storage">
<i className={`las la-file-alt`}></i>
</div>,
SYSTEM: <div className="rounded rounded-system">
<i className={`las la-server`}></i>
</div>,
APIS: <div className="rounded rounded-apis">
<i className={`las la-code`}></i>
</div>,
HELP: <div className="rounded rounded-help">
<i className={`las la-question`}></i>
</div>,
HELP_REGISTER: <div className="rounded rounded-login">
<i className={`las la-plus-circle`}></i>
</div>,
HELP_LOGIN: <div className="rounded rounded-login">
<i className={`las la-sign-in-alt`}></i>
</div>,
HELP_PASSWORDLESS: <div className="rounded rounded-login">
<i className={`las la-fingerprint`}></i>
</div>,
HELP_PASSWORD: <div className="rounded rounded-password">
<svg xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" version="1.1" width="100%" height="100%" viewBox="0 0 24 24" fit="" preserveAspectRatio="xMidYMid meet" focusable="false">
<path d="M17,7H22V17H17V19A1,1 0 0,0 18,20H20V22H17.5C16.95,22 16,21.55 16,21C16,21.55 15.05,22 14.5,22H12V20H14A1,1 0 0,0 15,19V5A1,1 0 0,0 14,4H12V2H14.5C15.05,2 16,2.45 16,3C16,2.45 16.95,2 17.5,2H20V4H18A1,1 0 0,0 17,5V7M2,7H13V9H4V15H13V17H2V7M20,15V9H17V15H20M8.5,12A1.5,1.5 0 0,0 7,10.5A1.5,1.5 0 0,0 5.5,12A1.5,1.5 0 0,0 7,13.5A1.5,1.5 0 0,0 8.5,12M13,10.89C12.39,10.33 11.44,10.38 10.88,11C10.32,11.6 10.37,12.55 11,13.11C11.55,13.63 12.43,13.63 13,13.11V10.89Z"></path>
</svg>
</div>,
HELP_FACTORS: <div className="rounded rounded-login">
<i className={`las la-fingerprint`}></i>
</div>,
HELP_PHONE: <div className="rounded rounded-phone">
<i className={`las la-phone`}></i>
</div>,
HELP_EMAIL: <div className="rounded rounded-email">
<i className={`las la-at`}></i>
</div>,
HELP_SOCIAL: <div className="rounded rounded-login">
<i className={`las la-share-alt`}></i>
</div>,
START: (
<div className="custom-rounded custom-rounded-start">
<i className={`las la-play-circle`}></i>
</div>
),
TASKS: (
<div className="custom-rounded custom-rounded-start">
<i className={`las la-tasks`}></i>
</div>
),
ARCHITECTURE: (
<div className="custom-rounded custom-rounded-architecture">
<i className={`las la-sitemap`}></i>
</div>
),
INSTANCE: (
<div className="custom-rounded custom-rounded-instance">
<i className={`las la-industry`}></i>
</div>
),
LOGIN: (
<div className="custom-rounded custom-rounded-login">
<i className={`las la-sign-in-alt`}></i>
</div>
),
PRIVATELABELING: (
<div className="custom-rounded custom-rounded-privatelabel">
<i className={`las la-swatchbook`}></i>
</div>
),
TEXTS: (
<div className="custom-rounded custom-rounded-texts">
<i className={`las la-paragraph`}></i>
</div>
),
POLICY: (
<div className="custom-rounded custom-rounded-policy">
<i className={`las la-file-contract`}></i>
</div>
),
SERVICE: (
<div className="custom-rounded custom-rounded-service">
<i className={`las la-concierge-bell`}></i>
</div>
),
STORAGE: (
<div className="custom-rounded custom-rounded-storage">
<i className={`las la-database`}></i>
</div>
),
FOLDER: (
<div className="custom-rounded custom-rounded-storage">
<i className={`las la-folder`}></i>
</div>
),
FILE: (
<div className="custom-rounded custom-rounded-storage">
<i className={`las la-file-alt`}></i>
</div>
),
SYSTEM: (
<div className="custom-rounded custom-rounded-system">
<i className={`las la-server`}></i>
</div>
),
APIS: (
<div className="custom-rounded custom-rounded-apis">
<i className={`las la-code`}></i>
</div>
),
HELP: (
<div className="custom-rounded custom-rounded-help">
<i className={`las la-question`}></i>
</div>
),
HELP_REGISTER: (
<div className="custom-rounded custom-rounded-login">
<i className={`las la-plus-circle`}></i>
</div>
),
HELP_LOGIN: (
<div className="custom-rounded custom-rounded-login">
<i className={`las la-sign-in-alt`}></i>
</div>
),
HELP_PASSWORDLESS: (
<div className="custom-rounded custom-rounded-login">
<i className={`las la-fingerprint`}></i>
</div>
),
HELP_PASSWORD: (
<div className="custom-rounded custom-rounded-password">
<svg
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
version="1.1"
width="100%"
height="100%"
viewBox="0 0 24 24"
fit=""
preserveAspectRatio="xMidYMid meet"
focusable="false"
>
<path d="M17,7H22V17H17V19A1,1 0 0,0 18,20H20V22H17.5C16.95,22 16,21.55 16,21C16,21.55 15.05,22 14.5,22H12V20H14A1,1 0 0,0 15,19V5A1,1 0 0,0 14,4H12V2H14.5C15.05,2 16,2.45 16,3C16,2.45 16.95,2 17.5,2H20V4H18A1,1 0 0,0 17,5V7M2,7H13V9H4V15H13V17H2V7M20,15V9H17V15H20M8.5,12A1.5,1.5 0 0,0 7,10.5A1.5,1.5 0 0,0 5.5,12A1.5,1.5 0 0,0 7,13.5A1.5,1.5 0 0,0 8.5,12M13,10.89C12.39,10.33 11.44,10.38 10.88,11C10.32,11.6 10.37,12.55 11,13.11C11.55,13.63 12.43,13.63 13,13.11V10.89Z"></path>
</svg>
</div>
),
HELP_FACTORS: (
<div className="custom-rounded custom-rounded-login">
<i className={`las la-fingerprint`}></i>
</div>
),
HELP_PHONE: (
<div className="custom-rounded custom-rounded-phone">
<i className={`las la-phone`}></i>
</div>
),
HELP_EMAIL: (
<div className="custom-rounded custom-rounded-email">
<i className={`las la-at`}></i>
</div>
),
HELP_SOCIAL: (
<div className="custom-rounded custom-rounded-login">
<i className={`las la-share-alt`}></i>
</div>
),
};
export function ListElement({ link, iconClasses,roundClasses, label, type, title, description}) {
export function ListElement({
link,
iconClasses,
roundClasses,
label,
type,
title,
description,
}) {
return (
<a className={styles.listelement} href={link}>
{type ? type :
iconClasses && <div className={roundClasses}>
{ label ? <span className={styles.listlabel}>{label}</span>: <i className={`${iconClasses}`}></i> }
</div>
}
{type
? type
: iconClasses && (
<div className={roundClasses}>
{label ? (
<span className={styles.listlabel}>{label}</span>
) : (
<i className={`${iconClasses}`}></i>
)}
</div>
)}
<div>
<h3>{title}</h3>
<p className={styles.listelement.description}>{description}</p>
</div>
</a>
)
);
}
export function ListWrapper({children, title, columns}) {
export function ListWrapper({ children, title, columns }) {
return (
<div className={styles.listWrapper}>
{title && <span className={styles.listWrapperTitle}>{title}</span>}
{children}
</div>
)
);
}
export function HomeListWrapper({children, image}) {
export function HomeListWrapper({ children, image }) {
return (
<div className={styles.homerow}>
{image}
<div className={styles.homecontent}>
{children}
</div>
<div className={styles.homecontent}>{children}</div>
</div>
)
}
);
}

View File

@ -1,53 +1,10 @@
.apicard {
border-radius: 0.5rem;
display: flex;
flex-direction: column;
min-width: 200px;
background: var(--card-background);
padding: 1rem;
text-decoration: none;
transition: all 0.2 ease-in-out;
margin: 1rem 0;
}
.apiauth {
background: var(--apiauthbackground);
}
.apimgmt {
background: var(--apimgmtbackground);
}
.apiadmin {
background: var(--apiadminbackground);
}
.apisystem {
background: var(--apisystembackground);
}
.apiasset {
background: var(--apiassetbackground);
}
.apicard:hover {
text-decoration: none;
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),
0 2px 4px -1px rgba(0, 0, 0, 0.06);
}
/* .apicard h2 {
color: white;
}
.apicard a {
color: #bfc1cc;
} */
.apicard h3,
h4,
h5 {
/* color: white; */
margin: 0.5rem 0 0 0;
}
@ -55,26 +12,3 @@ h5 {
font-size: 14px;
margin: 0;
}
.fillspace {
flex: 1;
}
.bottom {
display: flex;
align-items: center;
}
.bottomicon {
width: 24px;
margin-right: 0.5rem;
color: var(--ifm-font-color-base);
}
.bottomspan {
font-size: 12px;
font-weight: 600;
color: var(--ifm-font-color-base);
text-transform: uppercase;
margin: 0;
}

View File

@ -1,24 +0,0 @@
.column {
display: grid;
grid-template-columns: 1fr;
grid-gap: 1rem;
}
.item {
border-radius: 1rem;
transition: all 0.2s ease;
padding: 1rem;
display: flex;
flex-direction: column;
}
.item:hover {
border-radius: 1rem;
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.12);
}
@media (min-width: 1180px) {
.column {
grid-template-columns: 1fr 1fr;
}
}

View File

@ -1,9 +1,7 @@
/* stylelint-disable docusaurus/copyright-header */
/**
* Any CSS included here will be global. The classic template
* bundles Infima by default. Infima is a CSS framework designed to
* work well for content-centric websites.
*/
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "../../static/icons/line-awesome/css/line-awesome.min.css";
@font-face {
@ -129,6 +127,9 @@
--footer-border: rgba(0, 0, 0, 0.12);
--card-border: rgba(135, 149, 161, 0.2);
--ifm-pagination-nav-color-hover: #000000;
--input-border: #1a191954;
--input-hover-border: #000000;
--input-background: #00000004;
}
pre code {
@ -303,6 +304,9 @@ h2 {
--footer-border: rgba(255, 255, 255, 0.12);
--card-border: rgba(135, 149, 161, 0.2);
--ifm-pagination-nav-color-hover: #ffffff;
--input-border: #f9f7f775;
--input-hover-border: #ffffff;
--input-background: #00000040;
}
.get-started:hover {
@ -325,7 +329,7 @@ main .container img {
box-shadow: 0 30px 60px rgba(0, 0, 0, 0.12);
}
.rounded {
.custom-rounded {
display: flex;
align-items: center;
justify-content: center;
@ -336,51 +340,51 @@ main .container img {
height: 40px;
}
.rounded svg {
.custom-rounded svg {
fill: white;
height: 1.5rem;
width: 1.5rem;
}
.rounded i {
.custom-rounded i {
color: white;
}
.rounded-start {
.custom-rounded-start {
background: linear-gradient(40deg, #059669 30%, #047857);
}
.rounded-password {
.custom-rounded-password {
background: linear-gradient(40deg, #f59e0b 30%, #b45309);
}
.rounded-login,
.rounded-register {
.custom-rounded-login,
.custom-rounded-register {
background: linear-gradient(40deg, #059669 30%, #047857);
}
.rounded-privatelabel,
.rounded-phone,
.rounded-email,
.rounded-storage,
.rounded-service {
.custom-rounded-privatelabel,
.custom-rounded-phone,
.custom-rounded-email,
.custom-rounded-storage,
.custom-rounded-service {
background: linear-gradient(40deg, #3b82f6 30%, #4f46e5);
}
.rounded-split {
.custom-rounded-split {
background: linear-gradient(40deg, #3b82f6, #4f46e5);
}
.rounded-texts,
.rounded-help,
.rounded-architecture {
.custom-rounded-texts,
.custom-rounded-help,
.custom-rounded-architecture {
background: linear-gradient(40deg, #dc2626 30%, #db2777);
}
.rounded-system,
.rounded-apis,
.rounded-policy,
.rounded-instance {
.custom-rounded-system,
.custom-rounded-apis,
.custom-rounded-policy,
.custom-rounded-instance {
background: linear-gradient(40deg, #1f2937, #111827);
}
@ -483,7 +487,7 @@ table th {
}
a {
transition: all 1s ease;
transition: all 0.2s ease;
}
.alert {

View File

@ -0,0 +1,42 @@
.inputwrapper {
display: flex;
flex-direction: column;
}
.label {
font-size: 14px;
margin-bottom: 2px;
}
.input {
box-sizing: border-box;
padding-inline-start: 10px;
outline: none;
display: inline-block;
text-align: start;
cursor: text;
transform: all 0.2 linear;
font-size: 1rem;
border: none;
border: 1px solid var(--input-border);
background-color: var(--input-background);
border-radius: 4px;
height: 40px;
padding: 10px;
max-width: 400px;
transition: border-color 0.15s ease-in-out,
background-color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1),
color 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
width: 100%;
color: var(--ifm-font-color-base);
margin-bottom: 2px;
}
input:hover {
border-color: var(--input-hover-border);
}
input:active,
input:focus {
border-color: var(--ifm-color-primary);
}

View File

@ -60,7 +60,7 @@ const features = [
<ListElement
link="docs/guides/solution-scenarios/introduction"
iconClasses="las la-paragraph"
roundClasses="rounded rounded-split"
roundClasses="custom-rounded custom-rounded-split"
label="B2C"
title="Solution Scenarios"
description=""
@ -255,14 +255,12 @@ function Feature({
const Gigi = () => {
return (
<div className={styles.gigiwrapper}>
<div className={styles.gigiwrapperrelative}>
<img height="151px" width="256px" src="/img/gigi.svg" />
<div className={styles.gigibanner}>ZITADEL Cloud OUT NOW! 🚀</div>
</div>
<div className={styles.gigiwrapper}>
<div className={styles.gigiwrapperrelative}>
<img height="151px" width="256px" src="/img/gigi.svg" />
<div className={styles.gigibanner}>ZITADEL Cloud OUT NOW! 🚀</div>
</div>
</div>
);
};
@ -270,9 +268,7 @@ export default function Home() {
const context = useDocusaurusContext();
const { siteConfig = {} } = context;
return (
<Layout
description={`${siteConfig.customFields.description}`}
>
<Layout description={`${siteConfig.customFields.description}`}>
<header className={clsx("hero", styles.heroBanner)}>
<div className="container">
<h1 className="hero__title">{siteConfig.title}</h1>

View File

@ -0,0 +1,10 @@
import React from "react";
import Footer from "@theme-original/Footer";
export default function FooterWrapper(props) {
return (
<>
<Footer {...props} />
</>
);
}

View File

@ -0,0 +1,12 @@
import React from "react";
import AuthRequestProvider from "../../utils/authrequest";
// import EnvironmentProvider from "../../utils/environment";
// Default implementation, that you can customize
export default function Root({ children }) {
return (
// <EnvironmentProvider>
<AuthRequestProvider>{children}</AuthRequestProvider>
// </EnvironmentProvider>
);
}

View File

@ -0,0 +1,90 @@
import React, { useState, useEffect } from "react";
export const AuthRequestContext = React.createContext(null);
export default ({ children }) => {
const [instance, setInstance] = useState("your-instance");
const [clientId, setClientId] = useState("your-client-id");
const [redirectUri, setRedirectUri] = useState("your-redirect-uri");
const [responseType, setResponseType] = useState("your-response-type");
const [scope, setScope] = useState("your-scope");
const [prompt, setPrompt] = useState("your-prompt");
const [authMethod, setAuthMethod] = useState("your-auth-method");
const [codeChallenge, setCodeChallenge] = useState("your-code-challenge");
const [codeVerifier, setCodeVerifier] = useState("your-code-verifier");
const [loginHint, setLoginHint] = useState("your-login-hint");
const [idTokenHint, setIdTokenHint] = useState("your-id-token-hint");
const [organizationId, setOrganizationId] = useState("your-organization-id");
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const instance_param = params.get("instance");
const client_id = params.get("client_id");
const redirect_uri = params.get("redirect_uri");
const response_type = params.get("response_type");
const scope_param = params.get("scope");
// optional parameters
const prompt_param = params.get("prompt");
const auth_method_param = params.get("auth_method");
const code_verifier_param = params.get("code_verifier");
const login_hint = params.get("login_hint");
const id_token_hint = params.get("id_token_hint");
const organization_id = params.get("organization_id");
setInstance(instance_param ?? "https://mydomain-xyza.zitadel.cloud/");
setClientId(client_id ?? "170086824411201793@yourapp");
setRedirectUri(
redirect_uri ?? "http://localhost:8080/api/auth/callback/zitadel"
);
setResponseType(response_type ?? "code");
setScope(scope_param ?? "openid email profile");
setPrompt(prompt_param ?? "");
setAuthMethod(auth_method_param ?? "(none) PKCE");
setCodeVerifier(code_verifier_param ?? "random-string");
// optional parameters
setLoginHint(login_hint ?? "johndoe@example.zitadel.cloud");
setIdTokenHint(id_token_hint ?? "[your-id-token]");
setOrganizationId(organization_id ?? "168811945419506433");
if (
instance_param ||
client_id ||
redirect_uri ||
response_type ||
scope_param ||
prompt_param ||
organization_id ||
login_hint ||
id_token_hint
) {
const example = document.getElementById("example");
if (example) {
example.scrollIntoView();
}
}
}, []);
const authRequest = {
instance: [instance, setInstance],
clientId: [clientId, setClientId],
redirectUri: [redirectUri, setRedirectUri],
responseType: [responseType, setResponseType],
scope: [scope, setScope],
prompt: [prompt, setPrompt],
authMethod: [authMethod, setAuthMethod],
codeChallenge: [codeChallenge, setCodeChallenge],
codeVerifier: [codeVerifier, setCodeVerifier],
loginHint: [loginHint, setLoginHint],
idTokenHint: [idTokenHint, setIdTokenHint],
organizationId: [organizationId, setOrganizationId],
};
return (
<AuthRequestContext.Provider value={authRequest}>
{children}
</AuthRequestContext.Provider>
);
};

View File

@ -0,0 +1,31 @@
import React, { useState, useEffect } from "react";
export const EnvironmentContext = React.createContext(null);
export default ({ children }) => {
const [instance, setInstance] = useState("your-instance");
const [clientId, setClientId] = useState("your-client-id");
useEffect(() => {
const params = new URLSearchParams(window.location.search); // id=123
const clientId = params.get("clientId");
const instance = params.get("instance");
const localClientId = localStorage.getItem("clientId");
const localInstance = localStorage.getItem("instance");
setClientId(clientId ?? localClientId ?? "");
setInstance(instance ?? localInstance ?? "");
}, []);
const environment = {
instance: [instance, setInstance],
clientId: [clientId, setClientId],
};
return (
<EnvironmentContext.Provider value={environment}>
{children}
</EnvironmentContext.Provider>
);
};

55
docs/tailwind.config.js Normal file
View File

@ -0,0 +1,55 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: ["class", '[data-theme="dark"]'],
content: ["./docs/**/*.{js,ts,jsx,tsx}", "./src/**/*.{js,jsx,ts,tsx}"],
corePlugins: { preflight: false },
theme: {
fontFamily: {
sans: ["Lato", "serif"],
},
extend: {
colors: {
zitadelpink: "#ff2069",
primary: {
dark: {
100: "#afd1f2",
200: "#7fb5ea",
300: "#4192e0",
400: "#2782dc",
500: "#2073c4",
600: "#1c64aa",
700: "#17548f",
800: "#134575",
900: "#0f355b",
},
},
background: {
dark: {
100: "#4a69aa",
200: "#395183",
300: "#243252",
400: "#1a253c",
500: "#111827",
600: "#080b12",
700: "#000000",
800: "#000000",
900: "#000000",
},
},
input: {
light: {
label: "#000000c7",
background: "#00000004",
border: "rgba(26,25,25,.2196078431);",
},
dark: {
label: "#ffffffc7",
background: "#00000020",
border: "rgba(249,247,247,.1450980392)",
},
},
},
},
},
plugins: [],
};

View File

@ -1873,6 +1873,18 @@
dependencies:
"@hapi/hoek" "^9.0.0"
"@headlessui/react@^1.7.4":
version "1.7.4"
resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.7.4.tgz#ba7f50fda20667276ee84fcd4c2a459aa26187e3"
integrity sha512-D8n5yGCF3WIkPsjEYeM8knn9jQ70bigGGb5aUvN6y4BGxcT3OcOQOKcM3zRGllRCZCFxCZyQvYJF6ZE7bQUOyQ==
dependencies:
client-only "^0.0.1"
"@heroicons/react@^2.0.13":
version "2.0.13"
resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.0.13.tgz#9b1cc54ff77d6625c9565efdce0054a4bcd9074c"
integrity sha512-iSN5XwmagrnirWlYEWNPdCDj9aRYVD/lnK3JlsC9/+fqGF80k8C7rl+1HCvBX0dBoagKqOFBs6fMhJJ1hOg1EQ==
"@jest/schemas@^29.0.0":
version "29.0.0"
resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.0.0.tgz#5f47f5994dd4ef067fb7b4188ceac45f77fe952a"
@ -2639,11 +2651,30 @@ acorn-import-assertions@^1.7.6:
resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9"
integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==
acorn-node@^1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8"
integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==
dependencies:
acorn "^7.0.0"
acorn-walk "^7.0.0"
xtend "^4.0.2"
acorn-walk@^7.0.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
acorn-walk@^8.0.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
acorn@^7.0.0:
version "7.4.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.0.4, acorn@^8.5.0, acorn@^8.7.1:
version "8.8.1"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73"
@ -2777,7 +2808,7 @@ anymatch@~3.1.2:
normalize-path "^3.0.0"
picomatch "^2.0.4"
arg@^5.0.0:
arg@^5.0.0, arg@^5.0.2:
version "5.0.2"
resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.2.tgz#c81433cc427c92c4dcf4865142dbca6f15acd59c"
integrity sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==
@ -2824,19 +2855,7 @@ at-least-node@^1.0.0:
resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2"
integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==
autoprefixer@10.4.7:
version "10.4.7"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.7.tgz#1db8d195f41a52ca5069b7593be167618edbbedf"
integrity sha512-ypHju4Y2Oav95SipEcCcI5J7CGPuvz8oat7sUtYj3ClK44bldfvtvcxK6IEK++7rqB7YchDGzweZIBG+SD0ZAA==
dependencies:
browserslist "^4.20.3"
caniuse-lite "^1.0.30001335"
fraction.js "^4.2.0"
normalize-range "^0.1.2"
picocolors "^1.0.0"
postcss-value-parser "^4.2.0"
autoprefixer@^10.3.7, autoprefixer@^10.4.12, autoprefixer@^10.4.7:
autoprefixer@^10.3.7, autoprefixer@^10.4.12, autoprefixer@^10.4.13, autoprefixer@^10.4.7:
version "10.4.13"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.13.tgz#b5136b59930209a321e9fa3dca2e7c4d223e83a8"
integrity sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==
@ -2951,6 +2970,11 @@ base16@^1.0.0:
resolved "https://registry.yarnpkg.com/base16/-/base16-1.0.0.tgz#e297f60d7ec1014a7a971a39ebc8a98c0b681e70"
integrity sha512-pNdYkNPiJUnEhnfXV56+sQy8+AaPcG3POZAUnwr4EeqCUZFz4u2PePbo3e5Gj4ziYPCWGUZT9RHisvJKnwFuBQ==
base64-js@^1.3.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
batch@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
@ -3075,7 +3099,7 @@ braces@^3.0.2, braces@~3.0.2:
dependencies:
fill-range "^7.0.1"
browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.18.1, browserslist@^4.20.3, browserslist@^4.21.3, browserslist@^4.21.4:
browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.6, browserslist@^4.18.1, browserslist@^4.21.3, browserslist@^4.21.4:
version "4.21.4"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.4.tgz#e7496bbc67b9e39dd0f98565feccdcb0d4ff6987"
integrity sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==
@ -3090,6 +3114,14 @@ buffer-from@^1.0.0:
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
buffer@^6.0.3:
version "6.0.3"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==
dependencies:
base64-js "^1.3.1"
ieee754 "^1.2.1"
bytes@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
@ -3134,7 +3166,7 @@ camel-case@^4.1.2:
pascal-case "^3.1.2"
tslib "^2.0.3"
camelcase-css@2.0.1:
camelcase-css@2.0.1, camelcase-css@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5"
integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==
@ -3154,7 +3186,7 @@ caniuse-api@^3.0.0:
lodash.memoize "^4.1.2"
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001335, caniuse-lite@^1.0.30001400, caniuse-lite@^1.0.30001426:
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001400, caniuse-lite@^1.0.30001426:
version "1.0.30001430"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001430.tgz#638a8ae00b5a8a97e66ff43733b2701f81b101fa"
integrity sha512-IB1BXTZKPDVPM7cnV4iaKaHxckvdr/3xtctB3f7Hmenx3qYBhGtTZ//7EllK66aKXW98Lx0+7Yr0kxBtIt3tzg==
@ -3320,6 +3352,11 @@ cli-table3@^0.6.2:
optionalDependencies:
"@colors/colors" "1.5.0"
client-only@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1"
integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==
clone-deep@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
@ -3336,7 +3373,7 @@ clone-response@^1.0.2:
dependencies:
mimic-response "^1.0.0"
clsx@^1.1.1, clsx@^1.2.1:
clsx@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
@ -3365,7 +3402,7 @@ color-name@1.1.3:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
color-name@~1.1.4:
color-name@^1.1.4, color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
@ -4366,6 +4403,11 @@ define-properties@^1.1.4:
has-property-descriptors "^1.0.0"
object-keys "^1.1.1"
defined@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.1.tgz#c0b9db27bfaffd95d6f61399419b893df0f91ebf"
integrity sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==
del@^6.1.1:
version "6.1.1"
resolved "https://registry.yarnpkg.com/del/-/del-6.1.1.tgz#3b70314f1ec0aa325c6b14eb36b95786671edb7a"
@ -4430,6 +4472,20 @@ detect-port@^1.3.0:
address "^1.0.1"
debug "4"
detective@^5.2.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.1.tgz#6af01eeda11015acb0e73f933242b70f24f91034"
integrity sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==
dependencies:
acorn-node "^1.8.2"
defined "^1.0.0"
minimist "^1.2.6"
didyoumean@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==
dir-glob@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
@ -4437,6 +4493,11 @@ dir-glob@^3.0.1:
dependencies:
path-type "^4.0.0"
dlv@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79"
integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==
dns-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
@ -4893,7 +4954,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
fast-glob@^3.2.11, fast-glob@^3.2.7, fast-glob@^3.2.9:
fast-glob@^3.2.11, fast-glob@^3.2.12, fast-glob@^3.2.7, fast-glob@^3.2.9:
version "3.2.12"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80"
integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
@ -5168,7 +5229,7 @@ glob-parent@^5.1.2, glob-parent@~5.1.2:
dependencies:
is-glob "^4.0.1"
glob-parent@^6.0.1:
glob-parent@^6.0.1, glob-parent@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3"
integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==
@ -5593,6 +5654,11 @@ icss-utils@^5.0.0, icss-utils@^5.1.0:
resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae"
integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==
ieee754@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
ignore@^5.1.9, ignore@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
@ -6046,7 +6112,7 @@ leven@^3.1.0:
resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==
lilconfig@^2.0.3:
lilconfig@^2.0.3, lilconfig@^2.0.5, lilconfig@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4"
integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==
@ -6403,7 +6469,7 @@ minimatch@3.1.2, minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1:
dependencies:
brace-expansion "^1.1.7"
minimist@^1.2.0, minimist@^1.2.5:
minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6:
version "1.2.7"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.7.tgz#daa1c4d91f507390437c6a8bc01078e7000c4d18"
integrity sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==
@ -6547,6 +6613,11 @@ object-assign@^4.1.0, object-assign@^4.1.1:
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
object-hash@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-3.0.0.tgz#73f97f753e7baffc0e2cc9d6e079079744ac82e9"
integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==
object-inspect@1.12.0:
version "1.12.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0"
@ -6824,6 +6895,11 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
pify@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
pkg-dir@^4.1.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
@ -6909,6 +6985,30 @@ postcss-discard-unused@5.1.0, postcss-discard-unused@^5.1.0:
dependencies:
postcss-selector-parser "^6.0.5"
postcss-import@^14.1.0:
version "14.1.0"
resolved "https://registry.yarnpkg.com/postcss-import/-/postcss-import-14.1.0.tgz#a7333ffe32f0b8795303ee9e40215dac922781f0"
integrity sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==
dependencies:
postcss-value-parser "^4.0.0"
read-cache "^1.0.0"
resolve "^1.1.7"
postcss-js@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.0.tgz#31db79889531b80dc7bc9b0ad283e418dce0ac00"
integrity sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==
dependencies:
camelcase-css "^2.0.1"
postcss-load-config@^3.1.4:
version "3.1.4"
resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.4.tgz#1ab2571faf84bb078877e1d07905eabe9ebda855"
integrity sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==
dependencies:
lilconfig "^2.0.5"
yaml "^1.10.2"
postcss-loader@6.2.1:
version "6.2.1"
resolved "https://registry.yarnpkg.com/postcss-loader/-/postcss-loader-6.2.1.tgz#0895f7346b1702103d30fdc66e4d494a93c008ef"
@ -7047,6 +7147,13 @@ postcss-modules-values@^4.0.0:
dependencies:
icss-utils "^5.0.0"
postcss-nested@6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-6.0.0.tgz#1572f1984736578f360cffc7eb7dca69e30d1735"
integrity sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==
dependencies:
postcss-selector-parser "^6.0.10"
postcss-normalize-charset@5.1.0, postcss-normalize-charset@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz#9302de0b29094b52c259e9b2cf8dc0879879f0ed"
@ -7178,6 +7285,14 @@ postcss-reduce-transforms@5.1.0, postcss-reduce-transforms@^5.1.0:
dependencies:
postcss-value-parser "^4.2.0"
postcss-selector-parser@^6.0.10:
version "6.0.11"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz#2e41dc39b7ad74046e1615185185cd0b17d0c8dc"
integrity sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==
dependencies:
cssesc "^3.0.0"
util-deprecate "^1.0.2"
postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9:
version "6.0.10"
resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
@ -7215,7 +7330,7 @@ postcss-unique-selectors@5.1.1, postcss-unique-selectors@^5.1.1:
dependencies:
postcss-selector-parser "^6.0.5"
postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
@ -7234,6 +7349,15 @@ postcss@^8.3.11, postcss@^8.3.5, postcss@^8.4.14, postcss@^8.4.17, postcss@^8.4.
picocolors "^1.0.0"
source-map-js "^1.0.2"
postcss@^8.4.18, postcss@^8.4.19:
version "8.4.19"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.19.tgz#61178e2add236b17351897c8bcc0b4c8ecab56fc"
integrity sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==
dependencies:
nanoid "^3.3.4"
picocolors "^1.0.0"
source-map-js "^1.0.2"
prepend-http@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
@ -7377,6 +7501,11 @@ queue@6.0.2:
dependencies:
inherits "~2.0.3"
quick-lru@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932"
integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==
randombytes@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
@ -7571,6 +7700,13 @@ react@^17.0.2:
loose-envify "^1.1.0"
object-assign "^4.1.1"
read-cache@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
integrity sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==
dependencies:
pify "^2.3.0"
readable-stream@^2.0.1:
version "2.3.7"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
@ -7784,7 +7920,7 @@ resolve-pathname@^3.0.0:
resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd"
integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==
resolve@^1.1.6, resolve@^1.14.2, resolve@^1.3.2:
resolve@^1.1.6, resolve@^1.1.7, resolve@^1.14.2, resolve@^1.22.1, resolve@^1.3.2:
version "1.22.1"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
@ -8395,6 +8531,35 @@ svgo@^2.5.0, svgo@^2.7.0, svgo@^2.8.0:
picocolors "^1.0.0"
stable "^0.1.8"
tailwindcss@^3.2.4:
version "3.2.4"
resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.2.4.tgz#afe3477e7a19f3ceafb48e4b083e292ce0dc0250"
integrity sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ==
dependencies:
arg "^5.0.2"
chokidar "^3.5.3"
color-name "^1.1.4"
detective "^5.2.1"
didyoumean "^1.2.2"
dlv "^1.1.3"
fast-glob "^3.2.12"
glob-parent "^6.0.2"
is-glob "^4.0.3"
lilconfig "^2.0.6"
micromatch "^4.0.5"
normalize-path "^3.0.0"
object-hash "^3.0.0"
picocolors "^1.0.0"
postcss "^8.4.18"
postcss-import "^14.1.0"
postcss-js "^4.0.0"
postcss-load-config "^3.1.4"
postcss-nested "6.0.0"
postcss-selector-parser "^6.0.10"
postcss-value-parser "^4.2.0"
quick-lru "^5.1.1"
resolve "^1.22.1"
tapable@^1.0.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
@ -9136,7 +9301,7 @@ xml-js@^1.6.11:
dependencies:
sax "^1.2.4"
xtend@^4.0.0, xtend@^4.0.1:
xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==