chore: docker site gen for docs, update npm base image, fix chrome in docs page, jwt profile (#1019)

* initial version with docker

* move folder

* use correct path

* remove typo scanner

* change in site

* move dockerignore

* use proper path

* docs: chrome moving header, max width table, overflow on mobile (#1012)

* fix: table renderer, chrome moving header, mobile table

* card elevation

* chore(deps): bump node from 12 to 15 in /build (#967)

Bumps node from 12 to 15.

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* docs(oauth2): jwt profile (#954)

* first draft of JWT profile

* additional infos

* WIP Claim matrix

* restructure docs

* extend matrix

* typo

* use correct translation

* order tables a to z

* claim description

* remark

* describe username

Co-authored-by: Florian Forster <ffo@ffo-macbook.localdomain>
Co-authored-by: Max Peintner <max@caos.ch>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
This commit is contained in:
Florian Forster 2020-12-01 16:35:58 +01:00 committed by GitHub
parent be17fd7c96
commit 3deedfe863
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 293 additions and 105 deletions

View File

@ -32,3 +32,11 @@ updates:
commit-message:
prefix: chore
include: scope
- package-ecosystem: "docker"
directory: "/site/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
commit-message:
prefix: chore
include: scope

View File

@ -17,15 +17,19 @@ jobs:
steps:
- name: Checkout Repo
uses: actions/checkout@v2
- name: Install and Build
run: |
npm install
npx sapper export --legacy
- uses: docker/build-push-action@v2
with:
context: .
file: ./site/dockerfile
platforms: linux/amd64
tags: zitadel:docs
push: false
outputs: type=local,dest=output
- name: Archive Production Artifact
uses: actions/upload-artifact@master
with:
name: export
path: site/__sapper__/export
path: output
deploydocs:
name: Deploy
needs: builddocs

View File

@ -1,19 +0,0 @@
name: Spellcheck
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
spellcheck:
name: Typo CI (GitHub Action)
runs-on: ubuntu-latest
timeout-minutes: 4
if: "!contains(github.event.head_commit.message, '[ci skip]')"
steps:
- name: TypoCheck
uses: typoci/spellcheck-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,42 +0,0 @@
# What language dictionaries should it use? Currently Typo CI supports:
# de
# en
# en_GB
# es
# fr
# it
# pt
# pt_BR
dictionaries:
- en
- en_GB
- de
# Any files/folders we should ignore?
excluded_files:
- ".codecov/*"
- ".github/*"
- "build/*"
- "k8s/*"
- "*.min.css"
- "*.css.map"
- "*.min.js"
- "*.js.map"
- "package-lock.json"
- "package.json"
- ".releaserc.js"
- ".typo-ci.yml"
- ".gitignore"
- "go.mod"
- "go.sum"
# Any typos we should ignore?
excluded_words:
- typoci
- idps
- ZITADEL's
- otel
- otlp
# Would you like filenames to also be spellchecked?
spellcheck_filenames: false

View File

@ -34,7 +34,7 @@ COPY internal/protoc/protoc-gen-authoption/authoption/options.proto authoption/o
## With this step we prepare all node_modules, this helps caching the build
## Speed up this step by mounting your local node_modules directory
#######################
FROM node:12 as npm-base
FROM node:15 as npm-base
WORKDIR console
COPY console/package.json console/package-lock.json ./
RUN npm install \

View File

@ -5,14 +5,20 @@ The documentation is built according to the structure of a docs `folder`[Folder]
## Running locally
Set up the project:
You can simply run the static site by using the docker-compose command below.
```bash
npm i
```Bash
COMPOSE_DOCKER_CLI_BUILD=1 DOCKER_BUILDKIT=1 docker-compose -f site/docker-compose.yml up --build
```
Start the server with `npm run dev`, and navigate to [localhost:3000](http://localhost:3000).
## Building locally
You can simply run the static site by using the docker-compose command below.
```Bash
DOCKER_BUILDKIT=1 docker build -f site/dockerfile . -t zitadel:docs -o docs
```
## Honorable Mentions
This project was created with the help of some components from [svelte](https://github.com/sveltejs/svelte)([MIT](https://github.com/sveltejs/svelte/blob/master/LICENSE)) as well as [site-kit](https://github.com/sveltejs/site-kit)([MIT](https://github.com/sveltejs/site-kit/blob/master/LICENSE)).
This project was created with the help of some components from [svelte](https://github.com/sveltejs/svelte)([MIT](https://github.com/sveltejs/svelte/blob/master/LICENSE)) as well as [site-kit](https://github.com/sveltejs/site-kit)([MIT](https://github.com/sveltejs/site-kit/blob/master/LICENSE)).

10
site/docker-compose.yml Normal file
View File

@ -0,0 +1,10 @@
version: "3.8"
services:
docs:
build:
context: ..
dockerfile: site/dockerfile
command: sh -c "npm run dev"
ports:
- 3000:3000

13
site/dockerfile Normal file
View File

@ -0,0 +1,13 @@
FROM node:15 as builder
COPY site/ /site/
WORKDIR /site
RUN npm install
RUN npx sapper export --legacy
FROM scratch as final
COPY --from=builder /site/__sapper__/export .

View File

@ -8,12 +8,12 @@ This chapter documents the [OpenID Connect 1.0](https://openid.net/connect/) and
Under normal circumstances **ZITADEL** need four domain names to operate properly.
| Domain Name | Example | Description |
|:------------|:--------------------|--------------------------------------------------------------------------------------------------------------------------------------|
| issuer | issuer.zitadel.ch | Provides the [OpenID Connect 1.0 Discovery Endpoint](#openid-connect-10-discovery) |
| api | api.zitadel.ch | All ZITADEL API's are located under this domain see [API explanation](develop#APIs) for details |
| login | accounts.zitadel.ch | The accounts.* page provides server renderer pages like login and register and as well the authorization_endpoint for OpenID Connect |
| console | console.zitadel.ch | With the console.* domain we serve the assets for the management gui |
| Domain Name | Example | Description |
|:------------|:----------------------|--------------------------------------------------------------------------------------------------------------------------------------|
| issuer | `issuer.zitadel.ch` | Provides the [OpenID Connect 1.0 Discovery Endpoint](#openid-connect-10-discovery) |
| api | `api.zitadel.ch` | All ZITADEL API's are located under this domain see [API explanation](develop#APIs) for details |
| login | `accounts.zitadel.ch` | The accounts.* page provides server renderer pages like login and register and as well the authorization_endpoint for OpenID Connect |
| console | `console.zitadel.ch` | With the console.* domain we serve the assets for the management gui |
#### OpenID Connect 1.0 Discovery
@ -50,36 +50,106 @@ For example with [zitadel.ch](zitadel.ch) this would be the domain [issuer.zitad
#### OAuth 2.0 Metadata
**ZITADEL** does not provide a OAuth 2.0 Metadata endpoint but instead provides a [OpenID Connect Discovery Endpoint](#openid-connect-10-discovery).
**ZITADEL** does not yet provide a OAuth 2.0 Metadata endpoint but instead provides a [OpenID Connect Discovery Endpoint](#openid-connect-10-discovery).
### Scopes
#### How scopes work
ZITADEL supports the usage of scopes as way of requesting information from the IAM and also instruct ZITADEL to do certain operations.
> TODO describe
#### Standard Scopes
| Scopes | Example | Description |
|:--------|:----------|------------------------------------------------------|
| openid | `openid` | When using openid connect this is a mandatory scope |
| profile | `profile` | Optional scope to request the profile of the subject |
| email | `email` | Optional scope to request the email of the subject |
| address | `address` | Optional scope to request the address of the subject |
#### Custom Scopes
> This feature is not yet released
#### Reserved Scopes
In addition to the standard compliant scopes we utilize the following scopes.
| Scope | Description | Example |
|:------------------------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------|
| urn:zitadel:iam:org:project:role:{rolename} | By using this scope a [client](administrate#clients) can request the claim urn:zitadel:iam:roles:rolename} to be asserted when possible. As an alternative approach you can enable all [roles](administrate#Roles) to be asserted from the [project](administrate#projects) a [client](administrate#clients) belongs to. See details [here](administrate#RBAC_Settings) | urn:zitadel:iam:org:project:role:user |
| urn:zitadel:iam:org:domain:primary:{domainname} | When requesting this scope **ZITADEL** will enforce that the user is a member of the selected organisation. If the organisation does not exist a failure is displayed | urn:zitadel:iam:org:domain:primary:acme.ch |
| urn:zitadel:iam:role:{rolename} | | |
| urn:zitadel:iam:org:project:id:{projectid}:aud | By adding this scope, the requested projectid will be added to the audience of the access and id token | ZITADEL Project: urn:zitadel:iam:org:project:id:69234237810729019:aud |
| Scopes | Example | Description |
|:------------------------------------------------|:-------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| urn:zitadel:iam:org:project:role:{rolename} | `urn:zitadel:iam:org:project:role:user` | By using this scope a [client](administrate#clients) can request the claim urn:zitadel:iam:roles:rolename} to be asserted when possible. As an alternative approach you can enable all [roles](administrate#Roles) to be asserted from the [project](administrate#projects) a [client](administrate#clients) belongs to. See details [here](administrate#RBAC_Settings) |
| urn:zitadel:iam:org:domain:primary:{domainname} | `urn:zitadel:iam:org:domain:primary:acme.ch` | When requesting this scope **ZITADEL** will enforce that the user is a member of the selected organization. If the organization does not exist a failure is displayed |
| urn:zitadel:iam:role:{rolename} | | |
| urn:zitadel:iam:org:project:id:{projectid}:aud | ZITADEL's Project id is `urn:zitadel:iam:org:project:id:69234237810729019:aud` | By adding this scope, the requested projectid will be added to the audience of the access and id token |
> If access to ZITADEL's API's is needed with a service user the scope `urn:zitadel:iam:org:project:id:69234237810729019:aud` needs to be used with the JWT Profile request
### Claims
> TODO describe
ZITADEL asserts claims on different places according to the corresponding specifications or project and clients settings.
Please check below the matrix for an overview where which scope is asserted.
| Claims | Userinfo | ID Token | Access Token |
|:------------------------------------------------|:-------------------|----------------------------------------|------------------------------------------|
| acr | Yes | Yes | No |
| address | Yes when requested | Yes only when response type `id_token` | No |
| amr | Yes | Yes | No |
| aud | No | Yes | Yes when JWT |
| auth_time | Yes | Yes | No |
| azp | No | Yes | Yes when JWT |
| email | Yes when requested | Yes only when response type `id_token` | No |
| email_verified | Yes when requested | Yes only when response type `id_token` | No |
| exp | No | Yes | Yes when JWT |
| family_name | Yes when requested | Yes when requested | No |
| gender | Yes when requested | Yes when requested | No |
| given_name | Yes when requested | Yes when requested | No |
| iat | No | Yes | Yes when JWT |
| iss | No | Yes | Yes when JWT |
| locale | Yes when requested | Yes when requested | No |
| name | Yes when requested | Yes when requested | No |
| nonce | No | Yes | No |
| phone | Yes when requested | Yes only when response type `id_token` | No |
| preferred_username | Yes when requested | Yes | No |
| sub | Yes | Yes | Yes when JWT |
| urn:zitadel:iam:org:domain:primary:{domainname} | Yes when requested | Yes when requested | Yes when JWT and requested |
| urn:zitadel:iam:org:project:roles:{rolename} | Yes when requested | Yes when requested or configured | Yes when JWT and requested or configured |
#### Standard Claims
| Claims | Example | Description |
|:-------------------|:-----------------------------------------|-----------------------------------------------------------------------------------------------|
| acr | TBA | TBA |
| address | `Teufener Strasse 19, 9000 St. Gallen` | TBA |
| amr | `pwd mfa` | Authentication Method References as defined in [RFC8176](https://tools.ietf.org/html/rfc8176) |
| aud | `69234237810729019` | By default all client id's and the project id is included |
| auth_time | `1311280969` | Unix time of the authentication |
| azp | `69234237810729234` | Client id of the client who requested the token |
| email | `road.runner@acme.ch` | Email Address of the subject |
| email_verified | `true` | Boolean if the email was verified by ZITADEL |
| exp | `1311281970` | Time the token expires as unix time |
| family_name | `Runner` | The subjects family name |
| gender | `other` | Gender of the subject |
| given_name | `Road` | Given name of the subject |
| iat | `1311280970` | Issued at time of the token as unix time |
| iss | `https://issuer.zitadel.ch` | Issuing domain of a token |
| locale | `en` | Language from the subject |
| name | `Road Runner` | The subjects full name |
| nonce | `blQtVEJHNTF0WHhFQmhqZ0RqeHJsdzdkd2d...` | The nonce provided by the client |
| phone | `+41 79 XXX XX XX` | Phone number provided by the user |
| preferred_username | `road.runner@acme.caos.ch` | ZITADEL's login name of the user. Consist of `username@primarydomain` |
| sub | `77776025198584418` | Subject ID of the user |
#### Custom Claims
> This feature is not yet released
#### Reserved Claims
| Claims | Description | Example |
|:------------------------------------------------|:------------|----------------------------------------------------------------------------------|
| urn:zitadel:iam:org:domain:primary:{domainname} | | `{"urn:zitadel:iam:org:domain:primary": "acme.ch"}` |
| urn:zitadel:iam:org:project:roles:{rolename} | | `{"urn:zitadel:iam:org:project:roles": [ {"user": {"id1": "acme.zitade.ch", "id2": "caos.ch"} } ] }` |
| urn:zitadel:iam:roles:{rolename} | | |
ZITADEL reserves some claims to assert certain data.
| Claims | Example | Description |
|:------------------------------------------------|:-----------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| urn:zitadel:iam:org:domain:primary:{domainname} | `{"urn:zitadel:iam:org:domain:primary": "acme.ch"}` | This claim represents the primary domain of the organization the user belongs to. |
| urn:zitadel:iam:org:project:roles:{rolename} | `{"urn:zitadel:iam:org:project:roles": [ {"user": {"id1": "acme.zitade.ch", "id2": "caos.ch"} } ] }` | When roles are asserted, ZITADEL does this by providing the `id` and `primaryDomain` below the role. This gives you the option to check in which organization a user has the role. |
| urn:zitadel:iam:roles:{rolename} | TBA | TBA |
### Grant Types
@ -89,12 +159,12 @@ For a list of supported or unsupported `Grant Types` please have a look at the t
|:------------------------------------------------------|:--------------------|
| Authorization Code | yes |
| Authorization Code with PKCE | yes |
| Implicit | yes |
| Resource Owner Password Credentials | no |
| Client Credentials | yes |
| Device Authorization | under consideration |
| Refresh Token | work in progress |
| Implicit | yes |
| JSON Web Token (JWT) Profile | partially |
| Refresh Token | work in progress |
| Resource Owner Password Credentials | no |
| Security Assertion Markup Language (SAML) 2.0 Profile | no |
| Token Exchange | work in progress |
@ -122,6 +192,82 @@ For a list of supported or unsupported `Grant Types` please have a look at the t
**Link to spec.** [JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants](https://tools.ietf.org/html/rfc7523)
##### Using JWTs as Authorization Grants
Our service user work with the JWT profile to authenticate them against ZITADEL.
1. Create or use an existing service user
2. Create a new key and download it
3. Generate a JWT with the structure below and sing it with the downloaded key
4. Send the JWT Base64 encoded to ZITADEL's token endpoint
5. Use the received access token
---
Key JSON
| Key | Example | Description |
|:-------|:--------------------------------------------------------------------|:-------------------------------------------------------------------|
| type | `"serviceaccount"` | The type of account, right now only serviceaccount is valid |
| keyId | `"81693565968772648"` | This is unique ID of the key |
| key | `"-----BEGIN RSA PRIVATE KEY-----...-----END RSA PRIVATE KEY-----"` | The private key generated by ZITADEL, this can not be regenerated! |
| userId | `78366401571647008` | The service users ID, this is the same as the subject from tokens |
```JSON
{
"type": "serviceaccount",
"keyId": "81693565968772648",
"key": "-----BEGIN RSA PRIVATE KEY-----...-----END RSA PRIVATE KEY-----",
"userId": "78366401571647008"
}
```
---
JWT
| Claim | Example | Description |
|:------|:------------------------------|:---------------------------------------------------------------------------------|
| aud | `"https://issuer.zitadel.ch"` | String or Array of intended audiences MUST include ZITADEL's issuing domain |
| exp | `1605183582` | Unix timestamp of the expiry, MUST NOT be longer than 1h |
| iat | `1605179982` | Unix timestamp of the creation singing time of the JWT |
| iss | `"http://localhost:50003"` | String which represents the requesting party |
| sub | `"77479219772321307"` | The subject ID of the service user, normally the `userId` from the json key file |
```JSON
{
"iss": "http://localhost:50003",
"sub": "77479219772321307",
"aud": "https://issuer.zitadel.ch",
"exp": 1605183582,
"iat": 1605179982
}
```
---
Access Token Request
| Parameter | Example | Description |
|:-------------|:----------------------------------------------------------------------------|:----------------------------------------------|
| Content-Type | `application/x-www-form-urlencoded` | |
| grant_type | `urn:ietf:params:oauth:grant-type:jwt-bearer` | Using JWTs as Authorization Grants |
| assertion | `eyJhbGciOiJSUzI1Ni...` | The base64 encoded JWT created above |
| scope | `openid profile email urn:zitadel:iam:org:project:id:69234237810729019:aud` | Scopes you would like to request from ZITADEL |
```BASH
curl --request POST \
--url https://api.zitadel.ch/oauth/v2/token \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer \
--data assertion=eyJhbGciOiJSUzI1Ni...
--data scope=openid profile email address
```
##### Using JWTs for Client Authentication
> Not yet supported
#### Token Exchange
**Link to spec.** [OAuth 2.0 Token Exchange](https://tools.ietf.org/html/rfc8693)

View File

@ -9,8 +9,8 @@
"start": "node __sapper__/build",
"cy:run": "cypress run",
"cy:open": "cypress open",
"test": "run-p --race dev cy:run",
"imageoptim": "imageoptim --imagealpha 'static/img/*.png'"
"test": "run-p --race dev cy:run",
"imageoptim": "imageoptim --imagealpha 'static/img/*.png'"
},
"dependencies": {
"@polka/send": "^0.4.0",

View File

@ -84,6 +84,21 @@
</script>
<style>
.overlay {
position: fixed;
top: var(--nav-h);
right: 0;
left: 0;
bottom: 0;
background: #00000050;
backdrop-filter: blur(10px);
visibility: hidden;
}
.overlay.visible {
visibility: visible;
}
aside {
position: fixed;
background-color: var(--side-nav-back);
@ -108,7 +123,7 @@
aside.open {
width: calc(100vw - 1.5rem);
height: calc(100vh - var(--nav-h) - 9rem);
height: calc(100vh - var(--nav-h) - 15rem);
}
aside.open::before {
@ -144,7 +159,7 @@
overflow-y: auto;
width: 100%;
height: 100%;
padding: 4em 1.6rem 2em 3.2rem;
padding: 4em 1.6rem 2em 0;
bottom: 2em;
}
@ -499,12 +514,15 @@
{/each}
</div>
<div class="overlay {show_contents ? 'visible' : ''}"></div>
<aside bind:this={aside} class="sidebar-container" class:open={show_contents}>
<div class="sidebar" on:click={() => (show_contents = false)}>
<a rel="prefetch" href="." class="home" title="Zitadel Docs">
<img src="logos/zitadel-logo-light.svg" alt="zitadel-logo" />
<span>DOCS</span>
</a>
<SearchTrigger on:click={handleSearch}/>
<!-- scroll container -->
@ -516,6 +534,7 @@
<button on:click={() => (show_contents = !show_contents)}>
<Icon name={show_contents ? 'las la-times' : 'las la-bars'} />
</button>
</aside>
{#if searchEnabled == true}

View File

@ -44,7 +44,7 @@
.reference-toc li {
display: block;
line-height: 1.2;
margin: 0 0 4rem 0;
margin: 0 0 4rem 0;
}
a {

View File

@ -31,7 +31,6 @@
display: flex;
align-items: center;
z-index: 1;
width: var(--sidebar-w);
justify-content: center;
}

View File

@ -22,12 +22,12 @@
"administratelink_orgs":"Organisationen bearbeiten",
"administratelink_projects":"Projekte bearbeiten",
"administratelink_apps":"Applikationen bearbeiten",
"developlink":"Architektur und Technologien",
"developlink":"ZITADEL APIs",
"developlink_desc":"Erfahren Sie mehr über die ZITADEL-APIs und wie Sie mit ihnen entwickeln können.",
"developlink_authapi":"Authentication API",
"developlink_mgmtapi":"Management API",
"developlink_adminapi":"Admin API",
"docslink":"Dokumentation",
"docslink":"Architektur und Technologien",
"docslink_desc":"Erfahren Sie mehr über Konstruktion- und Designprinzipien und eingesetzte Technologien.",
"docslink_principles":"Prizipien",
"docslink_architecture":"Architektur",

View File

@ -166,6 +166,11 @@
max-width: 500px;
flex: 1 0 auto;
max-height: 350px;
transition: box-shadow .2 ease;
}
.doc-container .doc:hover {
box-shadow: 0 1px 8px rgba(0,0,0,0.2);
}
.doc-container .doc img{

View File

@ -51,6 +51,19 @@ export default function generate_docs(dirpath, dir, lang) {
return '<div class="side-by-side"><div class="copy">';
};
renderer.table = (header, body) => {
if (body) body = '<tbody>' + body + '</tbody>';
return '<div class="table-wrapper">\n'
+ '<table>\n'
+ '<thead>\n'
+ header
+ '</thead>\n'
+ body
+ '</table>\n'
+ '</div>';
};
renderer.code = (source, lang) => {
source = source.replace(/^ +/gm, (match) => match.split(' ').join('\t'));

View File

@ -372,9 +372,33 @@ a.no-underline {
}
/* tables --------------------------------- */
.table-wrapper {
max-width: var(--linemax);
overflow-x: auto;
}
.table-wrapper::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, .3);
box-shadow: inset 0 0 6px rgba(0, 0, 0, .3);
background-color: #00000010;
border-radius: 8px;
}
.table-wrapper::-webkit-scrollbar {
width: 6px;
height: 6px;
background-color: #00000010;
}
.table-wrapper::-webkit-scrollbar-thumb {
background-color: #6c8eef30;
border-radius: 8px;
cursor: pointer;
}
table {
width: 100%;
font-size: var(--h5);
font-size: var(--h5);
}
td,
@ -563,6 +587,8 @@ input[type="checkbox"]:checked::after {
.zitadel-gallery {
display: flex;
width: 100%;
max-width: 56em;
flex-wrap: wrap;
}
.zitadel-gallery img {