zitadel/site/docs/architecture/03-openidoauth.md
Livio Amstutz fa2c54a227
chore(docs): describe introspect and update some outh / oidc parts (#1397)
* chore(docs): describe `Using JWTs for Client Authentication`

* backup

* restructure

* rollback tests

* Update 03-openidoauth.md

Small formatting

* Update 03-openidoauth.md

Co-authored-by: mffap <mpa@caos.ch>
2021-03-09 15:41:22 +01:00

35 KiB

title
OpenID Connect 1.0 & OAuth 2.0

Endpoints and Domains

This chapter documents the OpenID Connect 1.0 and OAuth 2.0 features provided by ZITADEL.

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
api api.zitadel.ch All ZITADEL API's are located under this domain see API explanation 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

The OpenID Connect Discovery Endpoint is located within the issuer domain. For example with zitadel.ch, issuer.zitadel.ch would be the domain. This would give us https://issuer.zitadel.ch/.well-known/openid-configuration.

Link to spec. OpenID Connect Discovery 1.0 incorporating errata set 1

authorization_endpoint

https://accounts.zitadel.ch/oauth/v2/authorize

The authorization_endpoint is located with the login page, due to the need of accessing the same cookie domain

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 for more possible values. Scopes are space delimited, e.g. openid email profile

Required parameters for PKCE (see PKCE guide for more information)

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

Optional 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
max_age Seconds since the last active successful authentication of the user
nonce Random string value to associate the client session with the ID Token and for replay attacks mitigation.
prompt If the Auth Server prompts the user for (re)authentication.
no prompt: the user will have to choose a session if more than one session exists
none: user must be authenticated without interaction, an error is returned otherwise
login: user must reauthenticate / provide a user name
select_account: user is prompted to select one of the existing sessions or create a new one
state Opaque value used to maintain state between the request and the callback. Used for Cross-Site Request Forgery (CSRF) mitigation as well.

Successful Code Response

Property Description
code Opaque string which will be necessary to request tokens on the token endpoint
state Unmodified state parameter from the request

Successful Implicit Response

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 Only returned if response_type included id_token
token_type Type of the access_token. Value is always Bearer

Error Response

Regardless of the authorization flow chosen, if an error occurs the following response will be returned to the redirect_uri.

If the redirect_uri is not provided, was not registered or anything other prevents the auth server form returning the response to the client, the error will be display directly to the user on the auth server

Property Description
error An OAuth / OIDC error_type
error_description Description of the error type or additional information of the error
state Unmodified state parameter from the request

token_endpoint

https://api.zitadel.ch/oauth/v2/token

Authorization Code Grant (Code Exchange)

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.

Depending on your authorization method you will have to provide additional parameters or headers:

When using client_secret_basic

Send your client_id and client_secret as Basic Auth Header. Check Client Secret Basic Auth Method on how to build it correctly.

When using client_secret_post

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

When using none (PKCE)

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

When using private_key_jwt

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](#Using JWTs for Client Authentication)
client_assertion_type Must be urn:ietf:params:oauth:client-assertion-type:jwt-bearer
JWT Profile Grant

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 Client Authentication](#Using JWTs for Client Authentication)
scope Scopes you would like to request from ZITADEL. Scopes are space delimited, e.g. openid email profile
curl --request POST \
  --url https://api.zitadel.ch/oauth/v2/token \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data grant_type=authorization_code \
  --data code=DKLvnksjndjsflkdjlkfgjslow... \
  --data client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer \
  --data client_assertion=eyJhbGciOiJSUzI1Ni...

introspection_endpoint

https://api.zitadel.ch/oauth/v2/introspection

Parameter Description
token An access token

Depending on your authorization method you will have to provide additional parameters or headers:

When using client_secret_basic

Send your client_id and client_secret as Basic Auth Header. Check Client Secret Basic Auth Method on how to build it correctly.


When using private_key_jwt

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
client_assertion_type must be urn:ietf:params:oauth:client-assertion-type:jwt-bearer
curl --request POST \
  --url https://api.zitadel.ch/oauth/v2/token \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer \
  --data client_assertion=eyJhbGciOiJSUzI1Ni... \
  --data token=VjVxyCZmRmWYqd3_F5db9Pb9mHR5fqzhn...

userinfo_endpoint

https://api.zitadel.ch/oauth/v2/userinfo

end_session_endpoint

https://accounts.zitadel.ch/oauth/v2/endsession

The end_session_endpoint is located with the login page, due to the need of accessing the same cookie domain

jwks_uri

https://api.zitadel.ch/oauth/v2/keys

Be aware that these keys can be rotated without any prior notice. We will however make sure that a proper kid is set with each key!

OAuth 2.0 Metadata

ZITADEL does not yet provide a OAuth 2.0 Metadata endpoint but instead provides a OpenID Connect Discovery Endpoint.

Scopes

ZITADEL supports the usage of scopes as way of requesting information from the IAM and also instruct ZITADEL to do certain operations.

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.

Scopes Example Description
urn:zitadel:iam:org:project:role:{rolename} urn:zitadel:iam:org:project:role:user By using this scope a client can request the claim urn:zitadel:iam:roles:rolename} to be asserted when possible. As an alternative approach you can enable all roles to be asserted from the project a client belongs to. See details here
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🆔{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

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 Introspection ID Token Access Token
acr No No Yes No
address When requested When requested When requested amd response_type id_token No
amr No No Yes No
aud No No Yes When JWT
auth_time No No Yes No
azp No No Yes When JWT
email When requested When requested When requested amd response_type id_token No
email_verified When requested When requested When requested amd response_type id_token No
exp No No Yes When JWT
family_name When requested When requested When requested amd response_type id_token No
gender When requested When requested When requested amd response_type id_token No
given_name When requested When requested When requested amd response_type id_token No
iat No No Yes When JWT
iss No No Yes When JWT
locale When requested When requested When requested amd response_type id_token No
name When requested When requested When requested amd response_type id_token No
nonce No No Yes No
phone When requested When requested When requested amd response_type id_token No
phone_verified When requested When requested When requested amd response_type id_token No
preferred_username (username when Introspect ) When requested When requested Yes No
sub Yes Yes Yes When JWT
urn:zitadel:iam:org:domain:primary:{domainname} When requested When requested When requested When JWT and requested
urn:zitadel:iam:org:project:roles:{rolename} When requested When requested When requested or configured 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
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

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

Auth Methods

Client Secret Basic

When using client_secret_basic on token or introspection endpoints, provide anAuthorization header with a Basic auth value in the following form:

Authorization: "Basic " + base64( formUrlEncode(client_id) + ":" + formUrlEncode(client_secret) )

Given the client_id 78366401571920522@amce and client_secret veryweaksecret!, this would result in the following Authorization header: Basic NzgzNjY0MDE1NzE5MjA1MjIlNDBhbWNlOnZlcnl3ZWFrc2VjcmV0JTIx

JWT with Private Key

When using private_key_jwt for token or introspection endpoints, provide a JWT as assertion generated with the following structure and signed with a downloaded key:


Key JSON

Key Example Description
type "application" The type of account, right now only application is valid
keyId "81693565968962154" 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!
clientId 78366401571920522@acme The client_id of the application, this is the same as the subject from tokens
appId 78366403256846242 The id of the application (just for completeness, not used for JWT)
{
	"type": "serviceaccount",
	"keyId": "81693565968962154",
	"key": "-----BEGIN RSA PRIVATE KEY-----...-----END RSA PRIVATE KEY-----",
	"clientId": "78366401571920522@acme",
	"appId": "78366403256846242"
}

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 "78366401571920522@acme" String which represents the requesting party (owner of the key), normally the clientID from the json key file
sub "78366401571920522@acme" The subject ID of the application, normally the clientID from the json key file
{
	"iss": "78366401571920522@acme",
	"sub": "78366401571920522@acme",
	"aud": "https://issuer.zitadel.ch",
	"exp": 1605183582,
	"iat": 1605179982
}

To identify your key, it is necessary that you provide a JWT with a kid header claim representing your keyId from the Key JSON:

{
	"alg": "RS256",
	"kid": "81693565968962154"
}

Grant Types

For a list of supported or unsupported Grant Types please have a look at the table below.

Grant Type Supported
Authorization Code yes
Authorization Code with PKCE yes
Client Credentials yes
Device Authorization under consideration
Implicit yes
JSON Web Token (JWT) Profile yes
Refresh Token work in progress
Resource Owner Password Credentials no
Security Assertion Markup Language (SAML) 2.0 Profile no
Token Exchange work in progress

Authorization Code

Link to spec. The OAuth 2.0 Authorization Framework Section 1.3.1

Proof Key for Code Exchange

Link to spec. Proof Key for Code Exchange by OAuth Public Clients

Implicit

Link to spec. The OAuth 2.0 Authorization Framework Section 1.3.2

Client Credentials

Link to spec. The OAuth 2.0 Authorization Framework Section 1.3.4

Refresh Token

Link to spec. The OAuth 2.0 Authorization Framework Section 1.5

JSON Web Token (JWT) Profile

Link to spec. JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants

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 sign 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
{
	"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 "77479219772321307" String which represents the requesting party (owner of the key), normally the userId from the json key file
sub "77479219772321307" The subject ID of the service user, normally the userId from the json key file
{
	"iss": "77479219772321307",
	"sub": "77479219772321307",
	"aud": "https://issuer.zitadel.ch",
	"exp": 1605183582,
	"iat": 1605179982
}

To identify your key, it is necessary that you provide a JWT with a kid header claim representing your keyId from the Key JSON:

{
	"alg": "RS256",
	"kid": "81693565968772648"
}

See JWT Profile Grant on Token Endpoint for usage.

Using JWTs for Client Authentication

See how to build a JWT for client authentication from the downloaded key.

Find out how to use it on the token endpoint or the introspection endpoint.

Token Exchange

Link to spec. OAuth 2.0 Token Exchange

Device Authorization

Link to spec. OAuth 2.0 Device Authorization Grant

Not Supported Grant Types

Resource Owner Password Credentials

Due to growing security concerns we do not support this grant type. With OAuth 2.1 it looks like this grant will be removed.

Link to spec. OThe OAuth 2.0 Authorization Framework Section 1.3.3

Security Assertion Markup Language (SAML) 2.0 Profile

Link to spec. Security Assertion Markup Language (SAML) 2.0 Profile for OAuth 2.0 Client Authentication and Authorization Grants