From d15a7bdee2cf280a55ad14293d710bf805859e91 Mon Sep 17 00:00:00 2001 From: peppelinux Date: Sat, 1 May 2021 19:16:16 +0200 Subject: [PATCH 1/4] * chore: http_params explained * fix: Token exchange is not a draft anymore * feat: added authz configuration section * fix: index links --- doc/source/contents/conf.rst | 38 ++++++++++++++++++++++ doc/source/contents/session_management.rst | 2 +- doc/source/contents/setup.md | 5 +++ doc/source/index.rst | 5 +-- 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/doc/source/contents/conf.rst b/doc/source/contents/conf.rst index 847c7942..46384059 100644 --- a/doc/source/contents/conf.rst +++ b/doc/source/contents/conf.rst @@ -265,6 +265,9 @@ An example:: httpc_params ------------ +Parameters submitted to the web client (python requests). +In this case the TLS certificate will not be verified, to be intended exclusively for development purposes + Example :: "httpc_params": { @@ -342,6 +345,41 @@ An example:: } }, +----- +authz +----- + +This configuration section refers to the authorization/authentication endpoint behaviour. +Scopes bound to an access token are strictly related to grant management, as part of what that endpoint does. +Regarding grant authorization we should have something like the following example. + +If you omit this section from the configuration (thus using some sort of default profile) +you'll have an Implicit grant authorization that leads granting nothing. +Add the below to your configuration and you'll see things changing. + + +An example:: + + "authz": { + "class": "oidcop.authz.AuthzHandling", + "kwargs": { + "grant_config": { + "usage_rules": { + "authorization_code": { + "supports_minting": ["access_token", "refresh_token", "id_token"], + "max_usage": 1 + }, + "access_token": {}, + "refresh_token": { + "supports_minting": ["access_token", "refresh_token"] + } + }, + "expires_in": 43200 + } + } + }, + + ----------- session_key ----------- diff --git a/doc/source/contents/session_management.rst b/doc/source/contents/session_management.rst index 61bd51ef..54dc39f5 100644 --- a/doc/source/contents/session_management.rst +++ b/doc/source/contents/session_management.rst @@ -158,7 +158,7 @@ might normally ask the user for usage consent and then base the construction of the grant on that consent. If an authorization server can act as a Security Token Service (STS) as -defined by https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16 +defined by `Token Exchange [RFC-8693] `_ then no user is involved. In the context of session management the STS is equivalent to a user. diff --git a/doc/source/contents/setup.md b/doc/source/contents/setup.md index 0a4ed8be..ba965744 100644 --- a/doc/source/contents/setup.md +++ b/doc/source/contents/setup.md @@ -1,5 +1,10 @@ Setup ----- +Install + + pip install oidcop + + To configure a standard OIDC Provider you have to edit the oidcop configuration file. See `example/flask_op/config.json` to get in. diff --git a/doc/source/index.rst b/doc/source/index.rst index 2b23548b..9c6dc77e 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -8,13 +8,14 @@ A Python implementation of an **OIDC Provider** on top of `jwtconnect.io `_ * `OpenID Connect Session Management 1.0 `_ * `OpenID Connect Back-Channel Logout 1.0 `_ +* `OpenID Connect Front-Channel Logout 1.0 `_ * `OAuth2 Token introspection `_ It also supports the followings `add_ons` modules. -* `Custom scopes, that extends [OIDC standard ScopeClaims] `_ -* `PKCE, [Proof Key for Code Exchange by OAuth Public Clients] `_ +* Custom scopes, that extends `[OIDC standard ScopeClaims] `_ +* `Proof Key for Code Exchange by OAuth Public Clients (PKCE) `_ The entire project code is open sourced and therefore licensed From 446e7209a2a855c56b17d963d4a2c53079435131 Mon Sep 17 00:00:00 2001 From: peppelinux Date: Sun, 2 May 2021 15:05:59 +0200 Subject: [PATCH 2/4] chore: more Documentation, less README --- README.md | 225 +---------------------------------- doc/source/contents/conf.rst | 36 ++++-- doc/source/contents/setup.md | 90 ++++++++++++++ doc/source/contents/usage.md | 45 +++++++ doc/source/index.rst | 23 +++- 5 files changed, 187 insertions(+), 232 deletions(-) diff --git a/README.md b/README.md index 7188f1b8..e9a2c17b 100644 --- a/README.md +++ b/README.md @@ -2,232 +2,17 @@ Examples of a OIDC OPs with CherryPy, Flask and Django. **NOT** something you should even image running in a production environment. - -### Introduction - This project are here to show you how to 'build' an OP using the classes and functions provided by oidc-op. If you are just going to build a standard OP you only have to write the -configuration file. If you want to add or replace functionality this document -should be able to tell you how. - -Setting up an OP means making a number if decisions. Like, should the OP support: - -- [Web Finger](https://openid.net/specs/openid-connect-discovery-1_0.html#IssuerDiscovery) -- [dynamic discovery](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig) -- [dynamic client registration](https://openid.net/specs/openid-connect-registration-1_0.html) - -All these are services you can access at endpoints. The total set of endpoints -that this package supports are - -- webfinger -- provider_info -- registration -- authorization -- token -- refresh_token -- userinfo -- end_session - - -### Configuration directives - - -_issuer_ - -The issuer ID of the OP, unique value. - -_capabilities_ - -This covers most of the basic functionality of the OP. The key words are the -same as defined in -https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata . -A couple of things are defined else where. Like the endpoints, issuer id, -jwks_uri and the authentication methods at the token endpoint. - -An example: - - response_types_supported: - - code - - token - - id_token - - "code token" - - "code id_token" - - "id_token token" - - "code id_token token" - - none - response_modes_supported: - - query - - fragment - - form_post - subject_types_supported: - - public - - pairwise - grant_types_supported: - - authorization_code - - implicit - - urn:ietf:params:oauth:grant-type:jwt-bearer - - refresh_token - claim_types_supported: - - normal - - aggregated - - distributed - - claims_parameter_supported: True - request_parameter_supported: True - request_uri_parameter_supported: True - frontchannel_logout_supported: True - frontchannel_logout_session_supported: True - backchannel_logout_supported: True - backchannel_logout_session_supported: True - check_session_iframe: https://127.0.0.1:5000/check_session_iframe - - -_id_token_ - -Defines which class that handles creating an ID Token and possibly also -arguments used when initiating that class. - -An example: - - id_token: - class: oidcendpoint.id_token.IDToken - kwargs: - default_claims: - email: - essential: True - email_verified: - essential: True - - -### OIDC Provider example setup - -Create an environment -```` -virtualenv -ppython3 env -source env/bin/activate -```` - -##### Install oidc-op -```` -pip install git+https://github.com/rohe/oidc-op.git - -# get the usage examples -git clone https://github.com/rohe/oidc-op.git -```` - -##### Configure a Django OP - -See - -https://github.com/peppelinux/django-oidc-op - -##### Configure a Flask OP - -```` -pip install flask -cd oidc-op/ - -# configuration: create a private folder -cp -R flask_op/private . - -# copy required files -cp flask_op/passwd.json private/ -cp flask_op/conf.yaml private/ -cp -R flask_op/templates . - -# create a JWK for cookie signing -jwkgen --kty=SYM --kid cookie > private/cookie_sign_jwk.json -```` - -##### About JWK Set (JWKS) files -see: https://cryptojwt.readthedocs.io/en/latest/keyhandling.html - -You can use `cryptojwt.key_jar.init_key_jar` to create JWKS file. -An easy way can be to configure the auto creation of JWKS files directly in your conf.yaml file. -Using `read_only: False` in `OIDC_KEYS` it will create the path within the JWKS files. -Change it to `True` if you don't want to overwrite them on each execution. - -```` -# in conf.yaml -# -OIDC_KEYS: - 'private_path': './private/jwks.json' - 'key_defs': *keydef - 'public_path': './static/jwks.json' - # this will create the jwks files if they absent - 'read_only': False -```` - -In the JWTConnect-Python-CryptoJWT distribution there is also a script you can use to construct a JWK. - -You can for instance do: -```` -$ jwkgen --kty=RSA -{ - "d": "b9ucfay9vxDvz_nRZMVSUR9eRvHNMo0tc8Bl7tWkwxTis7LBXxmbMH1yzLs8omUil_u2a-Z_6VlKENxacuejYYcOhs6bfaU3iOqJbGi2p4t2i1oxjuF-cX6BZ5aHB5Wfb1uTXXobHokjcjVVDmBr_fNYBEPtZsVYqyN9sR9KE_ZLHEPks3IER09aX9G3wiB_PgcxQDRAl72qucsBz9_W9KS-TVWs-qCEqtXLmx9AAN6P8SjUcHAzEb0ZCJAYCkVu34wgNjxVaGyYN1qMA-1iOOVz--wtMyBwc5atSDBDgUApxFyj_DHSeBl81IHedcPjS9azxqFhumP7oJJyfecfSQ", - "e": "AQAB", - "kid": "cHZQbWRrMzRZak53U1pfSUNjY0dKd2xXaXRKenktdUduUjVBVTl3VE5ndw", - "kty": "RSA", - "n": "73XCXV2iiubSCEaFe26OpVnsBFlXwXh_yDCDyBqFgAFi5WdZTpRMJZoK0nn_vv2MvrXqFnw6IfXkwdsRGlMsNldVy36003gKa584CNksxfenwJZcF-huASUrSJEFr-3c0fMT_pLyAc7yf3rNCdRegzbBXSvIGKQpaeIjIFYftAPd9tjGA_SuYWVQDsSh3MeGbB4wt0lArAyFZ4f5o7SSxSDRCUF3ng3CB_QKUAaDHHgXrcNG_gPpgqQZjsDJ0VwMXjFKxQmskbH-dfsQ05znQsYn3pjcd_TEZ-Yu765_L5uxUrkEy_KnQXe1iqaQHcnfBWKXt18NAuBfgmKsv8gnxQ", - "p": "_RPgbiQcFu8Ekp-tC-Kschpag9iaLc9aDqrxE6GWuThEdExGngP_p1I7Qd7gXHHTMXLp1c4gH2cKx4AkfQyKny2RJGtV2onQButUU5r0gwnlqqycIA2Dc9JiH85PX2Z889TKJUlVETfYbezHbKhdsazjjsXCQ6p9JfkmgfBQOXM", - "q": "8jmgnadtwjMt96iOaoL51irPRXONO82tLM2AAZAK5Obsj23bZ9LFiw2Joh5oCSFdoUcRhbbIhCIv2aT4T_XKnDGnddrkxpF5Xgu0-hPNYnJx5m4kuzerot4j79Tx6qO-bshaaGz50MHs1vHSeFaDVN4fvh_hDWpV1BCNI0PKK-c" -} -SHA-256: pvPmdk34YjNwSZ_ICccGJwlWitJzy-uGnR5AU9wTNgw -```` - - -##### Run the server -```` -python -m flask_op.server private/conf.yaml -```` - -Then open your browser to `https://127.0.0.1:5000/.well-known/openid-configuration` to get the OpenID Provider Configuration resource. - - -##### Install OidcRP and configure flask-rp - -It uses `JWTConnect-Python-OidcRP` as Relaing Party for tests, see [related page](https://github.com/openid/JWTConnect-Python-OidcRP). -You can run a working instance of `JWTConnect-Python-OidcRP.flask_rp` with: - -```` -pip install git+https://github.com/openid/JWTConnect-Python-OidcRP.git - -# get entire project to have examples files -git clone https://github.com/openid/JWTConnect-Python-OidcRP.git -cd JWTConnect-Python-OidcRP - -# run it as it come -python3 -m flask_rp.wsgi flask_rp/conf.yaml - -# if you use django_op -RP_LOGFILE_NAME="./flrp.django.log" python3 -m flask_rp.wsgi django_op/example/data/oidc_rp/conf.django.yaml -```` - -Now you can connect to `https://127.0.0.1:8090/` to see the RP landing page and select your authentication endpoint. - - -### Authentication examples - -![RP](doc/images/1.png) - -Get to the RP landing page to choose your authentication endpoint. The first option aims to use _Provider Discovery_. - ----------------------------------- - -![OP Auth](doc/images/2.png) - -AS/OP accepted our authentication request and prompt to us the login form. Read passwd.json file to get credentials. - ----------------------------------- +configuration file. If you want to add or replace functionality please read the [Official Documentation](#TODO). -![Access](doc/images/3.png) -The identity representation with the information fetched from the user info endpoint. +# Contribute ----------------------------------- +-- -![Logout](doc/images/4.png) +# Authors -We can even test the single logout +- Roland Hedberg diff --git a/doc/source/contents/conf.rst b/doc/source/contents/conf.rst index 46384059..ba50cf5a 100644 --- a/doc/source/contents/conf.rst +++ b/doc/source/contents/conf.rst @@ -2,6 +2,12 @@ Configuration directives ======================== +------ +issuer +------ + +The issuer ID of the OP, a unique value in URI format. + ------ add_on ------ @@ -65,8 +71,7 @@ capabilities ------------ This covers most of the basic functionality of the OP. The key words are the -same as defined in -https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata . +same as defined in `OIDC Discovery `_. A couple of things are defined else where. Like the endpoints, issuer id, jwks_uri and the authentication methods at the token endpoint. @@ -293,13 +298,6 @@ An example:: "essential": true }}}}, - ------- -issuer ------- - -The issuer ID of the OP. - ---- keys ---- @@ -468,3 +466,23 @@ An example:: } } +This is somethig that can be customized. +For example in a django project we would use something like +the following (see `example/django_op/oidc_provider`): + + "userinfo": { + "class": "oidc_provider.users.UserInfo", + "kwargs": { + # map claims to django user attributes here: + "claims_map": { + "phone_number": "telephone", + "family_name": "last_name", + "given_name": "first_name", + "email": "email", + "verified_email": "email", + "gender": "gender", + "birthdate": "get_oidc_birthdate", + "updated_at": "get_oidc_lastlogin" + } + } + } diff --git a/doc/source/contents/setup.md b/doc/source/contents/setup.md index ba965744..85e6aeef 100644 --- a/doc/source/contents/setup.md +++ b/doc/source/contents/setup.md @@ -1,10 +1,100 @@ Setup ----- +Create an environment + + virtualenv -ppython3 env + source env/bin/activate + Install pip install oidcop +Get the usage examples + + git clone https://github.com/rohe/oidc-op.git + cd oidc-op/example/ + To configure a standard OIDC Provider you have to edit the oidcop configuration file. See `example/flask_op/config.json` to get in. + + ~/DEV/IdentityPython/OIDC/oidc-op/example/flask_op$ bash run.sh + 2021-05-02 14:57:44,727 root DEBUG Configured logging using dictionary + 2021-05-02 14:57:44,728 oidcop.configure DEBUG Set server password to {'kty': 'oct', 'use': 'sig', 'k': 'n4G9OjOixYMOotXvP15grwq0peN2zq9I'} + * Serving Flask app "oidc_op" (lazy loading) + * Environment: production + WARNING: This is a development server. Do not use it in a production deployment. + Use a production WSGI server instead. + * Debug mode: on + 2021-05-02 14:57:44,764 werkzeug INFO * Running on https://127.0.0.1:5000/ (Press CTRL+C to quit) + 2021-05-02 14:57:44,765 werkzeug INFO * Restarting with stat + 2021-05-02 14:57:45,011 root DEBUG Configured logging using dictionary + 2021-05-02 14:57:45,011 oidcop.configure DEBUG Set server password to {'kty': 'oct', 'use': 'sig', 'k': 'bceYal7bK9zvlBAA7-23lsi5crcv_8Cd'} + 2021-05-02 14:57:45,037 werkzeug WARNING * Debugger is active! + 2021-05-02 14:57:45,092 werkzeug INFO * Debugger PIN: 560-973-597 + + +Then open your browser to `https://127.0.0.1:5000/.well-known/openid-configuration` to get the OpenID Provider Configuration resource. + + +-------------------- +JWK Set (JWKS) files +-------------------- +see: `https://cryptojwt.readthedocs.io/en/latest/keyhandling.html`_ + + +You can use `cryptojwt.key_jar.init_key_jar` to create JWKS file. +An easy way can be to configure the auto creation of JWKS files directly in your conf.yaml file. +Using `read_only: False` in `OIDC_KEYS` it will create the path within the JWKS files. +Change it to `True` if you don't want to overwrite them on each execution. + +In genral configuration: + + OIDC_KEY_DEFS = [ + { + "type": "RSA", + "use": [ + "sig" + ] + }, + { + "type": "EC", + "crv": "P-256", + "use": [ + "sig" + ] + } + ] + + OIDCOP_CONF = { + "port": PORT, + "domain": DOMAIN, + "server_name": SERVER_NAME, + "base_url": f"https://{SERVER_NAME}", + "key_def": OIDC_KEY_DEFS, + "OIDC_KEYS": { + "private_path": "data/oidc_op/private/jwks.json", + "key_defs": OIDC_KEY_DEFS, + "public_path": "data/static/jwks.json", + "read_only": False, + "uri_path": "static/jwks.json" + }, + +In the JWTConnect-Python-CryptoJWT distribution there is also a script you can use to construct a JWK. You can for instance do: + + $ jwkgen --kty=RSA + { + "d": "b9ucfay9vxDvz_nRZMVSUR9eRvHNMo0tc8Bl7tWkwxTis7LBXxmbMH1yzLs8omUil_u2a-Z_6VlKENxacuejYYcOhs6bfaU3iOqJbGi2p4t2i1oxjuF-cX6BZ5aHB5Wfb1uTXXobHokjcjVVDmBr_fNYBEPtZsVYqyN9sR9KE_ZLHEPks3IER09aX9G3wiB_PgcxQDRAl72qucsBz9_W9KS-TVWs-qCEqtXLmx9AAN6P8SjUcHAzEb0ZCJAYCkVu34wgNjxVaGyYN1qMA-1iOOVz--wtMyBwc5atSDBDgUApxFyj_DHSeBl81IHedcPjS9azxqFhumP7oJJyfecfSQ", + "e": "AQAB", + "kid": "cHZQbWRrMzRZak53U1pfSUNjY0dKd2xXaXRKenktdUduUjVBVTl3VE5ndw", + "kty": "RSA", + "n": "73XCXV2iiubSCEaFe26OpVnsBFlXwXh_yDCDyBqFgAFi5WdZTpRMJZoK0nn_vv2MvrXqFnw6IfXkwdsRGlMsNldVy36003gKa584CNksxfenwJZcF-huASUrSJEFr-3c0fMT_pLyAc7yf3rNCdRegzbBXSvIGKQpaeIjIFYftAPd9tjGA_SuYWVQDsSh3MeGbB4wt0lArAyFZ4f5o7SSxSDRCUF3ng3CB_QKUAaDHHgXrcNG_gPpgqQZjsDJ0VwMXjFKxQmskbH-dfsQ05znQsYn3pjcd_TEZ-Yu765_L5uxUrkEy_KnQXe1iqaQHcnfBWKXt18NAuBfgmKsv8gnxQ", + "p": "_RPgbiQcFu8Ekp-tC-Kschpag9iaLc9aDqrxE6GWuThEdExGngP_p1I7Qd7gXHHTMXLp1c4gH2cKx4AkfQyKny2RJGtV2onQButUU5r0gwnlqqycIA2Dc9JiH85PX2Z889TKJUlVETfYbezHbKhdsazjjsXCQ6p9JfkmgfBQOXM", + "q": "8jmgnadtwjMt96iOaoL51irPRXONO82tLM2AAZAK5Obsj23bZ9LFiw2Joh5oCSFdoUcRhbbIhCIv2aT4T_XKnDGnddrkxpF5Xgu0-hPNYnJx5m4kuzerot4j79Tx6qO-bshaaGz50MHs1vHSeFaDVN4fvh_hDWpV1BCNI0PKK-c" + } + SHA-256: pvPmdk34YjNwSZ_ICccGJwlWitJzy-uGnR5AU9wTNgw + +Example: create a JWK for cookie signing + + jwkgen --kty=SYM --kid cookie > private/cookie_sign_jwk.json diff --git a/doc/source/contents/usage.md b/doc/source/contents/usage.md index daa57869..f63be14f 100644 --- a/doc/source/contents/usage.md +++ b/doc/source/contents/usage.md @@ -2,3 +2,48 @@ Usage ----- Some examples, how to run flask_op and django_op, but also some typical configuration in relation to common use cases. + + + +Configure flask-rp +------------------ + +_JWTConnect-Python-OidcRP_ is Relaing Party for tests, see [related page](https://github.com/openid/JWTConnect-Python-OidcRP). +You can run a working instance of `JWTConnect-Python-OidcRP.flask_rp` with: + +```` +pip install git+https://github.com/openid/JWTConnect-Python-OidcRP.git + +# get entire project to have examples files +git clone https://github.com/openid/JWTConnect-Python-OidcRP.git +cd JWTConnect-Python-OidcRP + +# run it as it come +python3 -m flask_rp.wsgi flask_rp/conf.yaml +```` + +Now you can connect to `https://127.0.0.1:8090/` to see the RP landing page and select your authentication endpoint. + +### Authentication examples + +![RP](doc/source/_images/1.png) + +Get to the RP landing page to choose your authentication endpoint. The first option aims to use _Provider Discovery_. + +---------------------------------- + +![OP Auth](doc/source/_images/2.png) + +AS/OP accepted our authentication request and prompt to us the login form. Read passwd.json file to get credentials. + +---------------------------------- + +![Access](doc/source/_images/3.png) + +The identity representation with the information fetched from the user info endpoint. + +---------------------------------- + +![Logout](doc/source/_images/4.png) + +We can even test the single logout diff --git a/doc/source/index.rst b/doc/source/index.rst index 9c6dc77e..b59f944b 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -1,9 +1,16 @@ Welcome to Idpy OIDC-op Documentation ====================================== -A Python implementation of an **OIDC Provider** on top of `jwtconnect.io `_ with the following features: +This project is a Python implementation of an **OIDC Provider** on top of `jwtconnect.io `_ +that shows you how to 'build' an OP using the classes and functions provided by oidc-op. + +If you are just going to build a standard OP you only have to write the configuration file. If you want to add or replace functionality this documentation +should be able to tell you how. + +Idpy OIDC-op implements the following standards: * `OpenID Connect Core 1.0 incorporating errata set 1 `_ +* `Web Finger `_ * `OpenID Connect Discovery 1.0 incorporating errata set 1 `_ * `OpenID Connect Dynamic Client Registration 1.0 incorporating errata set 1 `_ * `OpenID Connect Session Management 1.0 `_ @@ -11,12 +18,22 @@ A Python implementation of an **OIDC Provider** on top of `jwtconnect.io `_ * `OAuth2 Token introspection `_ - -It also supports the followings `add_ons` modules. +It also comes with the following `add_on` modules. * Custom scopes, that extends `[OIDC standard ScopeClaims] `_ * `Proof Key for Code Exchange by OAuth Public Clients (PKCE) `_ +All these are services you can access at endpoints. The total set of endpoints +that this package supports are + +- webfinger +- provider_info +- registration +- authorization +- token +- refresh_token +- userinfo +- end_session The entire project code is open sourced and therefore licensed under the `Apache 2.0 `_. From 1cd22aa83011cd614780bb150097b56fdecda179 Mon Sep 17 00:00:00 2001 From: peppelinux Date: Tue, 4 May 2021 15:45:53 +0200 Subject: [PATCH 3/4] Documentation * fix: according to https://github.com/IdentityPython/oidc-op/commit/65253b6745ebdb0fc767a8ee0c730c03c4fb39fc --- doc/source/contents/conf.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/contents/conf.rst b/doc/source/contents/conf.rst index ba50cf5a..dc31454e 100644 --- a/doc/source/contents/conf.rst +++ b/doc/source/contents/conf.rst @@ -55,7 +55,7 @@ An example:: "db": { "class": "oidcop.util.JSONDictDB", "kwargs": { - "json_path": "passwd.json" + "filename": "passwd.json" } }, "page_header": "Testing log in", From 2228a5e8aeb7090f6ad42d56d51607df84e5238d Mon Sep 17 00:00:00 2001 From: peppelinux Date: Tue, 4 May 2021 17:10:24 +0200 Subject: [PATCH 4/4] chore: added session_key example --- doc/source/contents/session_management.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/source/contents/session_management.rst b/doc/source/contents/session_management.rst index 54dc39f5..5f76ab61 100644 --- a/doc/source/contents/session_management.rst +++ b/doc/source/contents/session_management.rst @@ -95,6 +95,9 @@ item the user id. If you want the client session information the key is a list with 2 items (user_id, client_id). And lastly if you want a grant then the key is a list with 3 elements (user_id, client_id, grant_id). +Example:: + "diana;;KtEST70jZx1x;;85544c9cace411ebab53559c5425fcc0" + A *session identifier* is constructed using the **session_key** function. It takes as input the 3 elements list.::