website/docs: add source property mappings, rework provider property mappings (#10652)

This commit is contained in:
Marc 'risson' Schmitt
2024-08-07 21:30:29 +02:00
committed by GitHub
parent 9343e3495a
commit 322ae4c4ed
28 changed files with 308 additions and 82 deletions

View File

@ -16,7 +16,7 @@ export abstract class BasePropertyMappingForm<T extends PropertyMapping> extends
string
> {
docLink(): string {
return "/docs/property-mappings/expression?utm_source=authentik";
return "/docs/providers/property-mappings/expression?utm_source=authentik";
}
getSuccessMessage(): string {

View File

@ -9,6 +9,10 @@ import { LDAPSourcePropertyMapping, PropertymappingsApi } from "@goauthentik/api
@customElement("ak-property-mapping-ldap-source-form")
export class PropertyMappingLDAPSourceForm extends BasePropertyMappingForm<LDAPSourcePropertyMapping> {
docLink(): string {
return "/docs/sources/property-mappings/expression?utm_source=authentik";
}
loadInstance(pk: string): Promise<LDAPSourcePropertyMapping> {
return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsSourceLdapRetrieve({
pmUuid: pk,

View File

@ -9,6 +9,10 @@ import { OAuthSourcePropertyMapping, PropertymappingsApi } from "@goauthentik/ap
@customElement("ak-property-mapping-oauth-source-form")
export class PropertyMappingOAuthSourceForm extends BasePropertyMappingForm<OAuthSourcePropertyMapping> {
docLink(): string {
return "/docs/sources/property-mappings/expression?utm_source=authentik";
}
loadInstance(pk: string): Promise<OAuthSourcePropertyMapping> {
return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsSourceOauthRetrieve({
pmUuid: pk,

View File

@ -162,7 +162,7 @@ export class PropertyMappingRACForm extends ModelForm<RACPropertyMapping, string
target="_blank"
rel="noopener noreferrer"
href="${docLink(
"/docs/property-mappings/expression?utm_source=authentik",
"/docs/providers/property-mappings/expression?utm_source=authentik",
)}"
>
${msg("See documentation for a list of all variables.")}

View File

@ -9,6 +9,10 @@ import { PropertymappingsApi, SAMLSourcePropertyMapping } from "@goauthentik/api
@customElement("ak-property-mapping-saml-source-form")
export class PropertyMappingSAMLSourceForm extends BasePropertyMappingForm<SAMLSourcePropertyMapping> {
docLink(): string {
return "/docs/sources/property-mappings/expression?utm_source=authentik";
}
loadInstance(pk: string): Promise<SAMLSourcePropertyMapping> {
return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsSourceSamlRetrieve({
pmUuid: pk,

View File

@ -9,6 +9,10 @@ import { PropertymappingsApi, SCIMSourcePropertyMapping } from "@goauthentik/api
@customElement("ak-property-mapping-scim-source-form")
export class PropertyMappingSCIMSourceForm extends BasePropertyMappingForm<SCIMSourcePropertyMapping> {
docLink(): string {
return "/docs/sources/property-mappings/expression?utm_source=authentik";
}
loadInstance(pk: string): Promise<SCIMSourcePropertyMapping> {
return new PropertymappingsApi(DEFAULT_CONFIG).propertymappingsSourceScimRetrieve({
pmUuid: pk,

View File

@ -61,9 +61,9 @@ See [Flows](../flow/index.md)
### Property Mappings
Property Mappings allow you to make information available for external applications. For example, if you want to login to AWS with authentik, you'd use Property Mappings to set the user's roles in AWS based on their group memberships in authentik.
Property Mappings allow you to make information available for external applications, and to modify how information from sources are stored in authentik. For example, if you want to log in to AWS with authentik, you'd use property mappings to set the user's roles in AWS based on their group memberships in authentik.
See [Property Mappings](../property-mappings/index.md)
See [Providers Property Mappings](../providers/property-mappings/index.md) and [Source Property Mappings](../sources/property-mappings/index.md).
### Outpost

View File

@ -63,7 +63,7 @@ A flag which decides whether or not this field is required.
A field placeholder, shown within the input field.
By default, the placeholder is interpreted as-is. If you enable _Interpret placeholder as expression_, the placeholder
will be evaluated as a python expression. This happens in the same environment as [_Property mappings_](../../../property-mappings/expression).
will be evaluated as a Python expression. This happens in the same environment as [_Policies_](../../../policies/expression).
In the case of `Radio Button Group` and `Dropdown` prompts, this field defines all possible values (choices). When interpreted as-is, only one value will be allowed (the placeholder string). When interpreted as expression, a list of values can be returned to define multiple choices. For example, `return ["first option", 42, "another option"]` defines 3 possible values.
@ -78,7 +78,7 @@ The prompt's initial value. It can also be left empty, in which case the field w
With the `hidden` prompt, the initial value will also be the actual value, because the field is hidden to the user.
By default, the initial value is interpreted as-is. If you enable _Interpret initial value as expression_, the initial value
will be evaluated as a python expression. This happens in the same environment as [_Property mappings_](../../../property-mappings/expression).
will be evaluated as a Python expression. This happens in the same environment as [_Policies_](../../../policies/expression).
In the case of `Radio Button Group` and `Dropdown` prompts, this field defines the default choice. When interpreted as-is, the default choice will be the initial value string. When interpreted as expression, the default choice will be the returned value. For example, `return 42` defines `42` as the default choice.

View File

@ -1,30 +0,0 @@
---
title: Overview
---
Property Mappings allow you to pass information to external applications. For example, pass the current user's groups as a SAML parameter. Property Mappings are also used to map Source fields to authentik fields, for example when using LDAP.
## SAML Property Mapping
SAML Property Mappings allow you embed information into the SAML AuthN request. This information can then be used by the application to, for example, assign permissions to the object.
## LDAP Property Mapping
LDAP Property Mappings are used when you define a LDAP Source. These mappings define which LDAP property maps to which authentik property. By default, the following mappings are created:
- authentik default Active Directory Mapping: givenName
- authentik default Active Directory Mapping: sAMAccountName
- authentik default Active Directory Mapping: sn
- authentik default Active Directory Mapping: userPrincipalName
- authentik default LDAP Mapping: mail
- authentik default LDAP Mapping: Name
- authentik default OpenLDAP Mapping: cn
- authentik default OpenLDAP Mapping: uid
These are configured with most common LDAP setups.
You can also configure [custom LDAP property mappings](../sources/ldap/index.md#custom-ldap-property-mapping).
## Scope Mapping
Scope Mappings are used by the OAuth2 Provider to map information from authentik to OAuth2/OpenID Claims. Values returned by a Scope Mapping are added as custom claims to Access and ID tokens.

View File

@ -4,7 +4,7 @@ title: OAuth2 Provider
This provider supports both generic OAuth2 as well as OpenID Connect
Scopes can be configured using Scope Mappings, a type of [Property Mappings](../../property-mappings/#scope-mapping).
Scopes can be configured using scope mappings, a type of [property mapping](../property-mappings/index.md#scope-mappings).
| Endpoint | URL |
| -------------------- | -------------------------------------------------------------------- |

View File

@ -2,23 +2,23 @@
title: Expressions
---
The property mapping should return a value that is expected by the Provider/Source. Supported types are documented in the individual Provider/Source. Returning `None` is always accepted and would simply skip the mapping for which `None` was returned.
The property mapping should return a value that is expected by the provider. Supported types are documented in the individual provider. Returning `None` is always accepted and would simply skip the mapping for which `None` was returned.
## Available Functions
import Functions from "../expressions/_functions.md";
import Functions from "../../expressions/_functions.md";
<Functions />
## Variables
import Objects from "../expressions/_objects.md";
import Objects from "../../expressions/_objects.md";
<Objects />
import User from "../expressions/_user.md";
import User from "../../expressions/_user.md";
<User />
- `request`: The current request. This may be `None` if there is no contextual request. See ([Django documentation](https://docs.djangoproject.com/en/3.0/ref/request-response/#httprequest-objects))
- Other arbitrary arguments given by the provider, this is documented on the Provider/Source.
- Other arbitrary arguments given by the provider, this is documented on the provider.

View File

@ -0,0 +1,13 @@
---
title: Provider property mappings
---
Property mappings allow you to pass information to external applications. For example, pass the current user's groups as a SAML parameter.
## SAML property mappings
SAML property mappings allow you embed information into the SAML authentication request. This information can then be used by the application to, for example, assign permissions to the object.
## Scope mappings
Scope mappings are used by the OAuth2 provider to map information from authentik to OAuth2/OpenID claims. Values returned by a scope mapping are added as custom claims to access and ID tokens.

View File

@ -54,7 +54,7 @@ Next, you need to add a property mapping for each of the remote machines you wan
- **Enable font smoothing**: optional
- **Enable full window dragging**: optional
- Advanced settings:
- **Expressions**: optional, using Python you can define custom [expressions](../../property-mappings/expression.mdx).
- **Expressions**: optional, using Python you can define custom [expressions](../property-mappings/expression.mdx).
4. Click **Finish** to save your settings and close the modal.

View File

@ -2,7 +2,7 @@
title: SAML Provider
---
This provider allows you to integrate enterprise software using the SAML2 Protocol. It supports signed requests and uses [Property Mappings](../../property-mappings/#saml-property-mapping) to determine which fields are exposed and what values they return. This makes it possible to expose vendor-specific fields.
This provider allows you to integrate enterprise software using the SAML2 protocol. It supports signed requests and uses [property mappings](../property-mappings/#saml-property-mappings) to determine which fields are exposed and what values they return. This makes it possible to expose vendor-specific fields.
Default fields are exposed through auto-generated Property Mappings, which are prefixed with "authentik default".
| Endpoint | URL |

View File

@ -32,6 +32,20 @@ To try out the release candidate, replace your Docker image tag with the latest
**If you have any custom property mappings, we recommend migrating them to this new format.**
- **OAuth and SAML sources now sync groups by default**
OAuth (specifically OpenID and Okta) sources now sync groups by default when a `groups` claim is available.
SAML sources now sync groups by default when a `http://schemas.xmlsoap.org/claims/Group` attribute is available in the assertion.
To disable that behavior, create an OAuth/SAML source property mapping with the following expression:
```python
return {
"groups": [],
}
```
### Manual action may be required
- **Changes to the external user type**
@ -50,6 +64,8 @@ To try out the release candidate, replace your Docker image tag with the latest
## New features
- **Source property mappings for SCIM, OAuth, SAML and Plex sources**
- **SAML Source encryption support**
It is now possible to configure a SAML Source to decrypt and validate encrypted assertions. This can be configured by certaing a [Certificate-keypair](../../core/certificates.md) and selecting it in the SAML Source.

View File

@ -6,7 +6,7 @@ While authentik is secure out of the box, you can take steps to further increase
### Expressions
[Expressions](../property-mappings/expression.mdx) allow super-users and other highly privileged users to create custom logic within authentik to modify its behaviour. Editing/creating these expressions is, by default, limited to super-users and any related events are fully logged.
[Expressions](../policies/expression.mdx) allow super-users and other highly privileged users to create custom logic within authentik to modify its behaviour. Editing/creating these expressions is, by default, limited to super-users and any related events are fully logged.
However, for further hardening, it is possible to prevent any user (even super-users) from using expressions to create or edit any objects. To do so, configure your deployment to block API requests to these endpoints:

View File

@ -7,10 +7,11 @@ Sources allow you to connect authentik to an external user directory. Sources ca
### Find your source
Sources are in three general categories:
Sources are in the following general categories:
- **Protocols** ([LDAP](./ldap/index.md), [OAuth](./oauth/index.md), [SAML](./saml/index.md), and [SCIM](./scim/index.md))
- [**Property mappings**](./property-mappings/index.md) or how to import data from a source
- **Directory synchronization** (Active Directory, FreeIPA)
- **Protocols** (LDAP, OAuth, SAML, and SCIM)
- **Social logins** (Apple, Discord, Twitch, Twitter, and many others)
For instructions to add a specific source, refer to the documentation links in the left navigation pane.

View File

@ -45,7 +45,7 @@ To create or edit a source in authentik, open the Admin interface and navigate t
#### LDAP Attribute mapping
- **User Property mappings** and **Group Property Mappings**: Define which LDAP properties map to which authentik properties. The default set of property mappings is generated for Active Directory. See also [LDAP Property Mappings](../../../docs/property-mappings/#ldap-property-mapping).
- **User Property mappings** and **Group Property Mappings**: Define which LDAP properties map to which authentik properties. The default set of property mappings is generated for Active Directory. See also our documentation on [property mappings](#ldap-source-property-mappings).
#### Additional Settings
@ -65,11 +65,11 @@ To create or edit a source in authentik, open the Admin interface and navigate t
- **Object uniqueness field**: This field contains a unique identifier.
## Property mappings
## LDAP source property mappings
LDAP property mappings can be used to convert the raw LDAP response into an authentik user/group.
See the [overview](../property-mappings/index.md) for information on how property mappings work.
By default, authentik ships with [pre-configured mappings](../../property-mappings/index.md#ldap-property-mapping) for the most common LDAP setups. These mappings can be found on the LDAP Source Configuration page in the Admin interface.
By default, authentik ships with [pre-configured mappings](#built-in-property-mappings) for the most common LDAP setups. These mappings can be found on the LDAP Source Configuration page in the Admin interface.
You can assign the value of a mapping to any user attribute. Keep in mind though, data types from the LDAP server will be carried over. This means that with some implementations, where fields are stored as array in LDAP, they will be saved as array in authentik. To prevent this, use the built-in `list_flatten` function. Here is an example mapping for the user's username and a custom attribute for a phone number:
@ -82,19 +82,36 @@ return {
}
```
### Custom LDAP Property Mapping
### Built-in property mappings
If the default source mapping is not enough, you can set your own custom LDAP property mapping.
LDAP property mappings are used when you define a LDAP source. These mappings define which LDAP property maps to which authentik property. By default, the following mappings are created:
Here are the steps:
- authentik default Active Directory Mapping: givenName
- authentik default Active Directory Mapping: sAMAccountName
- authentik default Active Directory Mapping: sn
- authentik default Active Directory Mapping: userPrincipalName
- authentik default LDAP Mapping: mail
- authentik default LDAP Mapping: Name
- authentik default OpenLDAP Mapping: cn
- authentik default OpenLDAP Mapping: uid
1. In authentik, open the Admin interface, and then navigate to **Customization -> Property Mappings**.
2. Click **Create**, select **LDAP Property Mapping**, and then click **Next**.
3. Type a unique and meaningful **Name**, such as `ldap-displayName-mapping:name`.
4. In the**Object field** field, type the name of an existing authentik field, such as `name`. If you want to add more extended attributes, you can type `attributes.mobile` for example.
5. In the **Expression** field enter Python expressions to retrieve the value from LDAP source. For example `return list_flatten(ldap.get("displayName"))`.
These are configured with most common LDAP setups.
`list_flatten(["input string array"])` will convert a string array to a single string. If you are not sure whether the LDAP field is an array or not, you can map the field to any `attributes.xxx` and then check the sync result in authentik UI.
### Expression data
The following variables are available to LDAP source property mappings:
- `ldap`: A Python dictionary containing data from LDAP.
- `dn`: The object DN.
### Additional expression semantics
If you need to skip synchronization for a specific object, you can raise the `StopSync` exception:
```python
if ldap.get("cn") == "doNotSync":
raise StopSync
```
## Password login

View File

@ -31,3 +31,29 @@ This URL is fetched upon saving the source, and all the URLs will be replaced by
To simplify Machine-to-machine authentication, you can create an OAuth Source as "trusted" source of JWTs. Create a source and configure either the Well-known URL or the OIDC JWKS URL, or you can manually enter the JWKS data if you so desire.
Afterwards, this source can be selected in one or multiple OAuth2 providers, and any JWT issued by any of the configured sources' JWKS will be able to authenticate. To learn more about this, see [JWT-authentication](/docs/providers/oauth2/client_credentials#jwt-authentication).
## OAuth source property mappings
See the [overview](../property-mappings/index.md) for information on how property mappings work.
### Expression data
The following variables are available to OAuth source property mappings:
- `info`: A Python dictionary containing OAuth claims. For example (values might differ depending on the source):
```python
{
"iss": "https://source.company",
"sub": "f153e7da687eec8c8789c72b6cc6bb5197df7b48b263b3151f36908e1bc10691",
"aud": "01e4DmQiG1d3kaewD3Mkz7E7kXknk9j43eZMkNaE",
"aud": "a7809c1b1c4aaa50adfb68660a6273dd9c8d15e4",
"email": "user@authentik.company",
"email_verified": True,
"name": "User",
"given_name": "User",
"preferred_username": "user",
"nickname": "user",
}
```
- `client`: An OAuth client object to make requests to the Source with authentication built-in.
- `token`: A Python dictionary containing OAuth tokens.

View File

@ -25,3 +25,14 @@ Save, and you now have Plex as a source.
:::note
For more details on how-to have the new source display on the Login Page see [here](../index.md#add-sources-to-default-login-page).
:::
## Plex source property mappings
See the [overview](../property-mappings/index.md) for information on how property mappings work.
### Expression data
The following variables are available to OAuth source property mappings:
- `info`: A Python dictionary containing Plex user data.
- `auth_api`: A Plex client object to make requests to the Source with authentication built-in.

View File

@ -0,0 +1,21 @@
---
title: Sources expression property mappings
---
The property mapping should return a value that is expected by the source. Returning `None` is always accepted and would simply skip the mapping for which `None` was returned.
## Variables
- Arbitrary arguments given by the source (this is documented by the source).
- `properties`: A Python dictionary containing the result of the previously run property mappings, plus the initial data computed by the source.
- `request`: The current request. This may be `None` if there is no contextual request. See ([Django documentation](https://docs.djangoproject.com/en/3.0/ref/request-response/#httprequest-objects))
import Objects from "../../expressions/\_objects.md";
<Objects />
## Available Functions
import Functions from "../../expressions/\_functions.md";
<Functions />

View File

@ -0,0 +1,76 @@
---
title: Source property mappings
---
Source property mappings allow you to modify or gather extra information from sources.
This page is an overview of how property mappings work. For information about specific protocol, please refer to each protocol page:
- [LDAP](../ldap/#ldap-source-property-mappings)
- [OAuth](../oauth/#oauth-source-property-mappings)
- [SAML](../saml/#saml-source-property-mappings)
- [SCIM](../scim/#scim-source-property-mappings)
## Create a custom source property mapping
If the default source mappings are not enough, or if you need to get additional data from the source, you can create your own custom source property mappings.
Here are the steps:
1. In authentik, open the Admin interface, and then navigate to **Customization -> Property Mappings**.
2. Click **Create**, select the property mapping type for your source, and then click **Next**.
3. Type a unique and meaningful **Name**, such as `ldap-displayName-mapping:name`.
4. In the **Expression** field enter Python expressions to retrieve the value from the source. See [Expression Semantics](#expression-semantics) below for details.
5. In the source configuration, select the newly created property mapping as a **User property mapping** if it applies to users, or **Group property mapping** if it applies to groups.
## How it works
### Expression semantics
Each source provides the Python expression with additional data. You can import parts of that data into authentik users and groups. Assuming the source provides us with a `data` Python dictionary, you can write the following:
```python
return {
"name": data.get("displayName"),
}
```
You can see that the expression returns a Python dictionary. The dictionary keys must match [User properties](../../user-group-role/user/user_ref.md#object-properties) or [Group properties](../../user-group-role/groups/group_ref.md#object-properties). Note that for users, `ak_groups` and `group_attributes` cannot be set.
See each source documentation for a reference of the available data. See the authentik [expressions documentation](./expressions.md) for available data and functions.
Note that the [`list_flatten`](./expressions.md#list_flattenvalue-listany--any---optionalany) method is applied for all top-level properties, but not for attributes:
```python
return {
"username": data.get("username"), # list_flatten is automatically applied to top-level attributes
"attributes": {
"phone": list_flatten(data.get("phoneNumber")), # but not for attributes!
},
}
```
### Object construction process
A user or group object is constructed as follows:
1. The source provides initial properties based on commonly used data.
2. Each property mapping associated with the source is run and results are merged into the previous properties.
- If a property mapping throws an error, the process is aborted. If that happens inside a synchronization process, the object is skipped. If it happens during an enrollment or authentication flow, the flow is cancelled.
- If a property mapping sets one attribute to `None`, that attribute is then discarded.
3. If the `username` field is not set for user objects, or the `name` field is not set for group objects, the process is aborted.
4. The object is created or updated. The `attributes` property is merged with existing data if the object already exists.
### Group synchronization
LDAP and SCIM sources have built-in mechanisms to get groups. This section does not apply to them.
You can write a custom property mapping to set the user's groups:
```python
return {
"groups": data.get("groups", []),
}
```
The `groups` attribute is a special attribute that must contain group identifiers. By default, those identifiers are also used as the group name by default, those identifiers are also used as the group name. Each of those identifiers is then given to group property mappings as the `group_id` variable, if extra processing needs to happen.

View File

@ -80,3 +80,14 @@ This will depend heavily on what software you are using for your IDP. On the Met
</md:ContactPerson>
</md:EntityDescriptor>
```
## SAML source property mappings
See the [overview](../property-mappings/index.md) for information on how property mappings work.
### Expression data
The following variables are available to SAML source property mappings:
- `root`: An XML `ETree` object containing data from the source.
- `name_id`: An XML `Element` object identifying the user.

View File

@ -27,3 +27,13 @@ Endpoint to list, create, update and delete users.
Endpoint to list, create, update and delete groups.
There is also the `/v2/ServiceProviderConfig` and `/v2/ResourceTypes`, which is used by SCIM-enabled applications to find out which features authentik supports.
## SCIM source property mappings
See the [overview](../property-mappings/index.md) for information on how property mappings work.
### Expression data
The following variables are available to SCIM source property mappings:
- `data`: A Python dictionary containing data from the SCIM source.

View File

@ -0,0 +1,16 @@
---
title: Group properties and attributes
---
## Object properties
The Group object has the following properties:
- `name` Group's display name.
- `is_superuser` Boolean field if the group's users are superusers.
- `parent` The parent Group of this Group.
- `attributes` Dynamic attributes, see [Attributes](#attributes)
## Attributes
See [the user reference](../user/user_ref.md#attributes) for well-known attributes.

View File

@ -43,7 +43,7 @@ elif ak_is_group_member(request.user, name="Minio users"):
return None
```
Note that you can assign multiple policies to a user by returning a list, and returning `None` will map no policies to the user, resulting in no access to the MinIO instance. For more information on writing expressions, see [Expressions](../../../docs/property-mappings/expression) and [User](../../../docs/user-group-role/user/user_ref#object-properties) docs.
Note that you can assign multiple policies to a user by returning a list, and returning `None` will map no policies to the user, resulting in no access to the MinIO instance. For more information on writing expressions, see [Expressions](../../../docs/providers/property-mappings/expression) and [User](../../../docs/user-group-role/user/user_ref#object-properties) docs.
### Creating application and provider

View File

@ -50,3 +50,13 @@
from = "/integrations/sources/*"
to = "/docs/sources/:splat"
status = 302
# Split Property Mappings docs between Providers and Sources
[[redirects]]
from = "/docs/property-mappings/"
to = "/docs/providers/property-mappings/"
status = 302
[[redirects]]
from = "/docs/property-mappings/expression"
to = "/docs/providers/property-mappings/expression"
status = 302

View File

@ -74,6 +74,15 @@ const docsSidebar = {
id: "providers/index",
},
items: [
{
type: "category",
label: "Property Mappings",
link: {
type: "doc",
id: "providers/property-mappings/index",
},
items: ["providers/property-mappings/expression"],
},
{
type: "category",
label: "Google Workspace Provider",
@ -168,14 +177,6 @@ const docsSidebar = {
id: "sources/index",
},
items: [
{
type: "category",
label: "Directory synchronization",
items: [
"sources/active-directory/index",
"sources/freeipa/index",
],
},
{
type: "category",
label: "Protocols",
@ -186,6 +187,23 @@ const docsSidebar = {
"sources/scim/index",
],
},
{
type: "category",
label: "Property Mappings",
link: {
type: "doc",
id: "sources/property-mappings/index",
},
items: ["sources/property-mappings/expressions"],
},
{
type: "category",
label: "Directory synchronization",
items: [
"sources/active-directory/index",
"sources/freeipa/index",
],
},
{
type: "category",
label: "Social Logins",
@ -311,15 +329,6 @@ const docsSidebar = {
"policies/expression",
],
},
{
type: "category",
label: "Property Mappings",
link: {
type: "doc",
id: "property-mappings/index",
},
items: ["property-mappings/expression"],
},
{
type: "category",
label: "Events",
@ -374,7 +383,10 @@ const docsSidebar = {
type: "doc",
id: "user-group-role/groups/index",
},
items: ["user-group-role/groups/manage_groups"],
items: [
"user-group-role/groups/manage_groups",
"user-group-role/groups/group_ref",
],
},
{
type: "category",