docs(guides): Update metadata guide (#6072)

* wip new structure

* finalize

* broken link
This commit is contained in:
mffap
2023-06-26 14:48:12 +02:00
committed by GitHub
parent 2c6a2a376c
commit cef17b4a7a

View File

@@ -5,158 +5,57 @@ title: User Metadata
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
In this guide you will learn how to manually create the necessary requests to authenticate and request a user's metadata from ZITADEL.
This guide shows you how to request metadata from a user.
ZITADEL offers multiple methods to retrieve metadata.
Pick the one that works best for your solution.
Typical examples for user metadata include:
## Use cases for metadata
Typical use cases for user metadata include:
- Link the user to an internal identifier (eg, userId, contract number, etc.)
- Save custom user data when registering a user
- Route upstream traffic based on user attributes
## Prerequisites
## Before you start
### Create a new client
Before you start you need to add some metadata to an existing user.
You can do so by using [Console](../console/users) or [setting user metadata](/docs/apis/resources/mgmt/management-service-set-user-metadata) through the management API.
- Create a new [web application](../console/applications#web)
- Use Code-Flow
- In this example we will use `http://localhost` as redirect url
- Make sure to note the client secret
Most of the methods below require you to login with the correct user while setting some scopes.
Make sure you pick the right user when logging into the test application.
Use the [OIDC authentication request playground](/docs/apis/openidoauth/authrequest) or the configuration of an [example client](/docs/examples/introduction) to set the required scopes and receive a valid access token.
### Add metadata to a user
- [Add metadata](/guides/manage/customize/user-metadata) to a user
- Make sure you will use this user to login during later steps
## Requesting a token
:::info
In this guide we will manually request a token from ZITADEL for demonstration purposes. You will likely use a client library for the OpenID Authentication.
:::info Getting a token
In case you want to test out different settings configure an application with code flow (PKCE).
Grab the code from the url parameter after a successful login and exchange the code for tokens by calling the [token endpoint](/docs/apis/openidoauth/endpoints#token_endpoint).
You will find more information in our guides on how to [authenticate users](/docs/guides/integrate/login-users).
:::
### Set environment variables
## Use tokens to get user metadata
We will use some information throughout this guide. Set the required environment variables as follows. Make sure to replace the values with your information.
Use one of these methods to get the metadata for the currently logged in user.
```bash
export CLIENT_SECRET=QCiMffalakI...zpT0vuOsSkVk1ne \
export CLIENT_ID="16604...@docs-claims" \
export REDIRECT_URI="http://localhost" \
export ZITADEL_DOMAIN="https://...asd.zitadel.cloud"
```
<Tabs>
<TabItem value="go" label="Go" default>
Grab zitadel-tools to create the [required string](/apis/openidoauth/authn-methods#client-secret-basic) for Basic authentication:
```bash
git clone git@github.com:zitadel/zitadel-tools.git
cd zitadel-tools/cmd/basicauth
export BASIC_AUTH="$(go run basicauth.go -id $CLIENT_ID -secret $CLIENT_SECRET)"
```
</TabItem>
<TabItem value="python" label="Python">
```python
import base64
import urllib.parse
import os
clientId = os.environ.get("CLIENT_ID")
clientSecret = os.environ.get("CLIENT_SECRET")
escaped = safe_string = urllib.parse.quote_plus(clientId) + ":" + urllib.parse.quote_plus(clientSecret)
message_bytes = escaped.encode('ascii')
base64_bytes = base64.b64encode(message_bytes)
base64_message = base64_bytes.decode('ascii')
print(base64_message)
```
Export the result to the environment variable `BASIC_AUTH`.
</TabItem>
<TabItem value="js" label="Javascript" default>
```javascript
esc = encodeURIComponent(process.env.CLIENT_ID) + ":" + encodeURIComponent(process.env.CLIENT_SECRET)
enc = btoa(esc)
console.log(enc)
```
Export the result to the environment variable `BASIC_AUTH`.
</TabItem>
<TabItem value="manually" label="Manually">
You need to create a string as described [here](/apis/openidoauth/authn-methods#client-secret-basic).
Use a programming language of your choice or manually create the strings with online tools (don't use these secrets for production) like:
- https://www.urlencoder.org/
- https://www.base64encode.org/
Export the result to the environment variable `BASIC_AUTH`.
</TabItem>
</Tabs>
### 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) or try it out in our [OIDC Authrequest Playground](/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.
Grab the code paramter from the url (disregard the &code= parameter) and export the code as environment variable:
```bash
export AUTH_CODE="Y6nWsgR5WB...zUtFqSp5Xw"
```
### Token Request
```bash
curl --request POST \
--url "${ZITADEL_DOMAIN}/oauth/v2/token" \
--header "Accept: application/json" \
--header "Authorization: Basic ${BASIC_AUTH}" \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data grant_type=authorization_code \
--data-urlencode "code=$AUTH_CODE" \
--data-urlencode "redirect_uri=$REDIRECT_URI"
```
The result will give you something like:
```json
{
"access_token":"jZuRixKQTVecEjKqw...kc3G4",
"token_type":"Bearer",
"expires_in":43199,
"id_token":"ey...Ww"
}
```
Grab the access_token value and export as an environment variable:
```bash
export ACCESS_TOKEN="jZuRixKQTVecEjKqw...kc3G4"
```
In case you want to manage metadata for other users than the currently logged in user, then you must use the [management service](#manage-user-metadata-through-the-management-api).
### Request metadata from userinfo endpoint
With the access token we can make a request to the userinfo endpoint to get the user's metadata. This method is the preferred method to retrieve a user's information in combination with opaque tokens, to insure that the token is valid.
With the access token we can make a request to the [userinfo endpoint](/docs/apis/openidoauth/endpoints#introspection_endpoint) to get the user's metadata.
This method is the preferred method to retrieve a user's information in combination with opaque tokens, to insure that the token is valid.
You must pass the [reserved scope](/docs/apis/openidoauth/scopes#reserved-scopes) `urn:zitadel:iam:user:metadata` in your authentication request.
If you don't include this scope the response will contain user data, but not the metadata object.
Request the user information by calling the [userinfo endpoint](/docs/apis/openidoauth/endpoints#introspection_endpoint):
```bash
curl --request GET \
--url "${ZITADEL_DOMAIN}/oidc/v1/userinfo" \
--url "https://$ZITADEL_DOMAIN/oidc/v1/userinfo" \
--header "Authorization: Bearer $ACCESS_TOKEN"
```
Replace `$ACCESS_TOKEN` with your user's access token.
The response will look something like this
```json
@@ -178,15 +77,19 @@ The response will look something like this
}
```
You can grab the metadata from the reserved claim `"urn:zitadel:iam:user:metadata"` as key-value pairs. Note that the values are base64 encoded. So the value `MTIzNA` decodes to `1234`.
You can grab the metadata from the reserved claim `"urn:zitadel:iam:user:metadata"` as key-value pairs.
Note that the values are base64 encoded.
So the value `MTIzNA` decodes to `1234`.
### Send metadata inside the ID token (optional)
### Send metadata inside the ID token
Check "User Info inside ID Token" in the configuration of your application.
You might want to include metadata directly into the ID Token.
For that you need to enable "User Info inside ID Token" in your application's settings.
![](/img/console_projects_application_token_settings.png)
Now request a new token from ZITADEL.
Now request a new token from ZITADEL by logging in with the user that has metadata attached.
Make sure you log into the correct client/application where you enabled the settings.
The result will give you something like:
@@ -199,4 +102,129 @@ The result will give you something like:
}
```
Grab the id_token and inspect the contents of the token at [jwt.io](https://jwt.io/). You should get the same info in the ID token as when requested from the user endpoint.
When you decode the value of `id_token`, then the response will include the metadata claim:
```json
{
"amr": [
"password",
"pwd",
"mfa",
"otp"
],
"at_hash": "lGIblkTr8faHz2zd0oTddA",
"aud": [
"170086824411201793@portal",
"209806276543185153@portal",
"170086774599581953"
],
"auth_time": 1687418556,
"azp": "170086824411201793@portal",
"c_hash": "dA3wre4ytCJCn11f7cIm0A",
"client_id": "1700...1793@portal",
"email": "road.runner@zitadel.com",
"email_verified": true,
"exp": 1687422272,
"family_name": "Runner",
"given_name": "Road",
"iat": 1687418672,
"iss": "https://...-abcd.zitadel.cloud",
"locale": null,
"name": "Road Runner",
"preferred_username": "road.runner@...-abcd.zitadel.cloud",
"sub": "170848145649959169",
"updated_at": 1658329554,
//highlight-start
"urn:zitadel:iam:user:metadata": {
"ContractNumber": "MTIzNA"
}
//highlight-end
}
```
Note that the values are base64 encoded.
So the value `MTIzNA` decodes to `1234`.
:::info decoding the jwt token
Use a website like [jwt.io](https://jwt.io/) to decode the token.
With jq installed you can also use `jq -R 'split(".") | .[1] | @base64d | fromjson' <<< $ID_TOKEN`
:::
### Request metadata from authentication API
You can use the authentication service to request and search for the user's metadata.
The introspection endpoint and the token endpoint in the examples above do not require a special scope to access.
Yet when accessing the authentication service, you need to pass the [reserved scope](/docs/apis/openidoauth/scopes#reserved-scopes) `urn:zitadel:iam:org:project:id:zitadel:aud` along with the authentication request.
This scope allows the user to access ZITADEL's APIs, specifically the authentication API that we need for this method.
Use the [OIDC authentication request playground](/docs/apis/openidoauth/authrequest) or the configuration of an [example client](/docs/examples/introduction) to set the required scopes and receive a valid access token.
:::note Invalid audience
If you get the error "invalid audience (APP-Zxfako)", then you need to add the reserved scope `urn:zitadel:iam:org:project:id:zitadel:aud` to your authentication request.
:::
You can request the user's metadata with the [List My Metadata](/docs/apis/resources/auth/auth-service-list-my-metadata) method:
```bash
curl -L -X POST "https://$ZITADEL_DOMAIN/auth/v1/users/me/metadata/_search" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-H "Authorization: Bearer $ACCESS_TOKEN" \
--data-raw '{
"query": {
"offset": "0",
"limit": 100,
"asc": true
},
"queries": [
{
"keyQuery": {
"key": "$METADATA_KEY",
"method": "TEXT_QUERY_METHOD_EQUALS"
}
}
]
}'
```
Replace `$ACCESS_TOKEN` with your user's access token.
Replace `$ZITADEL_DOMAIN` with your ZITADEL instance's url.
Replace `$METADATA_KEY` with they key you want to search for (f.e. "ContractNumber")
:::info Get all metadata
You can omit the queries array to retrieve all metadata key-value pairs.
:::
An example response for your search looks like this:
```json
{
"details":{
"totalResult":"1",
"processedSequence":"2935",
"viewTimestamp":"2023-06-21T16:01:52.829838Z"
},
"result":[
{
"details":{
"sequence":"409",
"creationDate":"2022-08-04T09:09:06.259324Z",
"changeDate":"2022-08-04T09:09:06.259324Z",
"resourceOwner":"170086363054473473"
},
"key":"ContractNumber",
"value":"MTIzNA"
}
]
}
```
## Manage user metadata through the management API
The previous methods allowed you to retrieve metadata only for the `sub` in the access token.
In case you want to get the metadata for another user, you need to use the management service.
The user that calls the management service must have [manager permissions](/docs/guides/manage/console/managers).
A user can be either a human user or a service user.
You can get [metadata of a user filtered by your query](/docs/apis/resources/mgmt/management-service-list-user-metadata) or [get a metadata object from a user by a specific key](/docs/apis/resources/mgmt/management-service-get-user-metadata).
The management service allows you to set and delete metadata, see the [API documentation for users](/docs/category/apis/resources/mgmt/users).