.. _api_oauth2: OAuth 2 ======= .. _api_oauth2_general_info: General information ------------------- Before `OAuth2`_ authentication with pCon.login can be used a client has to be registered. To request registration of a new client please send an email with the following information to support@easterngraphics.com: .. _OAuth2: https://tools.ietf.org/html/rfc6749 :cliend_id: Client id of the application, must be unique and should be limited to [a-z-A-Z0-9\_-] :name: A descriptive name for the application :redirect_uris: URIs that are acceptable as return URL for this application More information on this is available in the description of the separate flows. Currently all registered URLs will also permit all subpaths. e.g: https://example.com/foo/oauth will permit all of the following urls: - https://example.com/foo/oauth - https://example.com/foo/oauth/sub1 - https://example.com/foo/oauth/sub2/sub3 :default_redirect_uri: Default redirect uri to use :required_scopes: Scopes that are required by the application (See :ref:`api_oauth2_scopes` and documentation of the APIs you want to use) :intended_flows: OAuth supports serveral diffent flows depending on the use case of the application. The flows supported by pCon.login are further described in this document. :supports_long_term_tokens: Whether to support :ref:`long term service tokens `. (this also implies that the refresh token flow will be enabled for this client) Usually this is not needed. :pcon_session: Whether the client is considered part of the common "pcon" session. This mainly effects logout behaviour: When the user logs out all tokens belonging to "pcon" clients will be expired. :contact_email: Email address of a person/group responsible for that client. We recommend a function-related email address (e.g. example-product-manager@company.com) to ensure the safe availability of a contact person even over extended periods of time. .. note:: OAuth usually includes a page where the end user has to confirm that a given application will now gain access to certain aspects of his account. Since all clients are manually approved upon registration and considered implicitly trusted for all users no such page is shown to the end user in pCon.login. .. important:: Make sure you store/transmit any received tokens as securely as possible Standard OAuth endpoints ------------------------ :Authorization: $base_url/api/oauth2/authorize :Request tokens: $base_url/api/oauth2/request_token :Revoke tokens: $base_url/api/oauth2/revoke_token .. note:: Access to the authorization enpoint should be done via redirect or in a new/ popup window. Access via iframe is not supported and may not work depending on the browsers security measures. Implementation recommendations ------------------------------ For web applications it is generally advisable to implement the authorization via the :ref:`api_oauth2_authorization_code_flow` in the server component of your application. Web applications that do not have a dedicated backend server can use our `javascript client library `_ to simplify implementation of the authorization code flow in browser applications. For native (desktop) applications we also offer a C library, please contact pm_p-log@easterngraphics.com for details. .. _api_oauth2_authorization_code_flow: Authorization code flow ----------------------- This is currenty the recommended flow for all applications. The following steps are taken in this flow: - the application redirects to the authorization endpoint of pCon.login - If the user is not yet logged in he will be asked to log in - Once the user is authenticated pCon.login will redirect back to the web application via the provided redirect_uri - the application extracts an authorization code from the url query parameters - The application *server* then request an access token See `OAuth2 Section 4.1`_ .. _OAuth2 Section 4.1: https://tools.ietf.org/html/rfc6749#section-4.1 Step 1: Obtain authorization code ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: GET $base_url/api/oauth2/authorize?client_id=$client_id&response_type=code&redirect_uri=$redirect_uri&state=6ix2wgfrcurpvcc7&code_challenge=luO5H6_7Q2V076_vLsQ7E8eHsO-z_DApcZFUVom_vPM&code_challenge_method=S256 ==> Location: $redirect_uri?code=sekrit&state=6ix2wgfrcurpvcc7 Parameters ++++++++++ :response_type: Must be set to ``code`` :client_id: The registered client id for the application :redirect_uri: Optional. URL that should be redirected to on success (default uri will be used if not specified) :state: Optional. Will be passed back to the application unchanged and should be used to avoid cross site request forgery. :scope: Optional. Space delimited list of required :ref:`api_oauth2_scopes` :code_challenge: `PKCE`_ code challenge. Please refer to `PKCE Section 4.1`_ for details on how this value should be constructed. :code_challenge_method: `PKCE`_ code challenge method. Only method S256 should be used. :force_login: Optional. Set this parameter to `1` to force the user to login again. If the user cancels the process he will be in a logged out state. :force_reauthentication: Optional. When this parameter is set to `1` the user will need to reenter his credentials even if already logged in. In contrast with `force_login` the user will remain logged in when the process is canceled. The intended use case for this option is confirming the identity of the user before performing dangerous or hard to revert actions. .. note:: Currently the user can change to a different account at this step. This may change in a future version of pCon.login .. _PKCE: https://tools.ietf.org/html/rfc7636 .. _PKCE Section 4.1: https://tools.ietf.org/html/rfc7636#section-4.1 Response ++++++++ Response values are encoded as ``application/x-www-form-urlencoded`` query parameters of the redirect_uri. :code: A short lived authorization code that should be used to obtain an access token :state: Any state parameter provided in the request For error responses and there possible causes please refer to `OAuth2 Section 4.1.2.1`_ .. _OAuth2 Section 4.1.2.1: https://tools.ietf.org/html/rfc6749#section-4.1.2.1 Step 2: Obtain access token ^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: POST $base_url/api/oauth2/request_token Authorization: Basic Y2xpZW50X2lkOnNla3JpdA== Content-type: application/x-www-form-urlencoded client_id=$client_id&grant_type=authorization_code&code=$code&redirect_uri=$redirect_uri ==> Content-type: application/json { "token_type": "Bearer", "access_token": "asdfg", "refresh_token": "ghjkl", "expires_in": 3600, "scope": "query_account" } Parameters ++++++++++ Parameters are encoded in the body of the post request as ``application/x-www-form-urlencoded`` If client credentials where issued, they must be provided via ``Basic`` authorization in the ``Authorization`` header :grant_type: Must be set to ``authorization_code`` :client_id: The registered client id for the application :code: The authorization code obtained in step 1 :redirect_uri: If included in step 1 the redirect uri must be provided here again and be identical to the uri given in step 1 :code_verifier: `PKCE`_ code verifier that was used to create the code_challenge in step 1 :wam_want_refresh_token: Optional. Set to 1 to indicate that the appplication wants to use refresh tokens :wam_refresh_token_app_infos: Optional. Provide text that helps identify where this token orignated from/ is used (e.g. a hostname to disambiguate multiple devices) Response ++++++++ The response is a json object with the following properties: :token_type: Type of token returend (currently always Bearer) :access_token: The issued access token :refresh_token: Optional. If a refresh token is provided it can be used to obtain new access_tokens. :expires_in: Seconds after which the access token will no longer be valid :scope: Indentical to the scope parameter of the request, or the default scope for the client For error responses and their possible causes please refer to `OAuth2 Section 5.2`_ .. _OAuth2 Section 5.2: https://tools.ietf.org/html/rfc6749#section-5.2 .. commented out in docs since we don't want to grant this to anyone .. it is only supported for legacy clients (DataClient / DataPool) .. Password credentials flow .. ------------------------- .. This exchanges the users credentials for access/ refresh tokens. .. Where possible this oauth flow should be avoided since it requires storing the .. user credentials by a 3rd party. .. .. See `OAuth2 Section 4.3`_ .. .. .. _OAuth2 Section 4.3: https://tools.ietf.org/html/rfc6749#section-4.3 .. .. :: .. .. POST $base_url/api/oauth2/request_token .. Authorization: Basic Y2xpZW50X2lkOnNla3JpdA== .. Content-type: application/x-www-form-urlencoded .. .. grant_type=password&username=$username&password=$password .. .. ==> .. .. Content-type: application/json .. .. { .. "token_type": "Bearer", .. "access_token": "asdfg", .. "refresh_token": "ghjkl", .. "expires_in": 3600, .. "scope": "query_account" .. } .. .. .. Parameters .. ^^^^^^^^^^ .. Parameters are encoded in the body of the post request as ``application/x-www-form-urlencoded`` .. If client credentials where issued, they must be provided via ``Basic`` .. authorization in the ``Authorization`` header .. .. :grant_type: Must be set to ``password`` .. :username: The login of the user .. :password: The Password of the user .. :scope: Optional. Space delimited list of required :ref:`api_oauth2_scopes` .. :client_id: If no client credentials where provided this parameter must be set .. to the client id, otherwise it should be omitted. .. :wam_want_refresh_token: Optional. Set to 1 to indicate that the appplication wants to use refresh tokens .. :wam_refresh_token_app_infos: Optional. Provide text that helps identify where this token orignated from/ is used .. (e.g. a hostname to disambiguate multiple devices) .. .. .. oauth2 spec does not say anything wrt. passing a client_id in the .. "no credentials" case, that seems to be the logical way to do it, but it might be .. an accidental feature of our oauth framework. .. .. .. .. Response .. ^^^^^^^^ .. The response is a json object with the following properties: .. .. :token_type: Type of token returend (currently always Bearer) .. :access_token: The issued access token .. :refresh_token: Optional. If a refresh token is provided it can be used to obtain new .. access_tokens. .. :expires_in: Seconds after which the access token will no longer be valid .. :scope: Optional. Space delimited list of required :ref:`api_oauth2_scopes` .. .. .. .. .. Client credentials workflow is also implemented, however we do not .. document it here since it is unlikely that anyone else will need it .. (it is required for p-ud) .. _api_oauth2_access_token_from_refresh_token: Acquire access token via refresh token -------------------------------------- Some OAuth flows can return a longer lived "refresh token" that can be used to acquire access tokens with the same (or fewer) scopes as during the acquisition of the refresh token. .. important:: Clients must not make any assumptions regarding the lifetime of a refresh token See `OAuth2 Section 6`_ .. _OAuth2 Section 6: https://tools.ietf.org/html/rfc6749#section-6 :: POST $base_url/api/oauth2/request_token Authorization: Basic Y2xpZW50X2lkOnNla3JpdA== Content-type: application/x-www-form-urlencoded grant_type=refresh_token&refresh_token=To5YDQ ==> Content-type: application/json { "token_type": "Bearer", "access_token": "asdfg", "refresh_token": "ghjkl", "expires_in": 3600, "scope": "query_account" } Parameters ^^^^^^^^^^ Parameters are encoded in the body of the post request as ``application/x-www-form-urlencoded`` If client credentials where issued, they must be provided via ``Basic`` authorization in the ``Authorization`` header :grant_type: Must be set to ``refresh_token`` :refresh_token: The refresh_token that was issued :scope: Optional. Space delimited list of required :ref:`api_oauth2_scopes` Must not include any scope that was not included at the time the refresh_token was acquired). :client_id: If no client credentials where provided this parameter must be set to the client id, otherwise it should be omitted. .. oauth2 spec does not say anything wrt. passing a client_id in the "no credentials" case, that seems to be the logical way to do it, but it might be an accidental feature of our oauth framework. Response ^^^^^^^^ The response is a json object with the following properties: :token_type: Type of token returend (currently always Bearer) :access_token: The issued access token :refresh_token: Optional. If this is included it replaces the refresh_token used in the request. .. important:: If you reduced the scopes, the new refresh_token will only allow access to these scopes. :expires_in: Seconds after which the access token will no longer be valid :scope: Optional. Space delimited list of required :ref:`api_oauth2_scopes` For error responses and their possible causes please refer to `OAuth2 Section 5.2`_ .. _api_oauth2_revoke_token: Revoking tokens --------------- Tokens will automatically expire after a while (this also includes refresh_tokens, unless otherwise noted). However it is also possible to explicitly revoke tokens that are no longer needed See `OAuth2 Token Revocation Section 2.1`_ .. _OAuth2 Token Revocation Section 2.1: https://tools.ietf.org/html/rfc7009#section-2.1 .. note:: Revoking a token may also revoke other related tokens (e.g. revoking an access_token may also invalidate associated refresh_token and vice versa) :: POST $base_url/api/oauth2/revoke_token Authorization: Basic Y2xpZW50X2lkOnNla3JpdA== Content-type: application/x-www-form-urlencoded token=To5YDQ&token_type_hint=refresh_token Parameters ^^^^^^^^^^ Parameters are encoded in the body of the post request as ``application/x-www-form-urlencoded`` If client credentials where issued, they must be provided via ``Basic`` authorization in the ``Authorization`` header :token: The token to revoke :token_type_hint: Optional. Specifies the type of the given token (either ``access_token`` or ``refresh_token``) :client_id: If no client credentials where provided this parameter must be set to the client id, otherwise it should be omitted. .. oauth2 spec does not say anything wrt. passing a client_id in the "no credentials" case, that seems to be the logical way to do it, but it might be an accidental feature of our oauth framework. Response ^^^^^^^^ If the token was sucessfully revoked the response will have HTTP status 200. .. note:: Passing an invalid token is not treated as an error .. _api_oauth2_scopes: Scopes ------ Scopes define which APIs can be accessed by a given client. At the time of this writing all scopes are statically granted or rejected based on the client registration and no explicit user confirmation takes place. The following scopes are currently available: :query_account: The most common permission, required to query information about the user/organization :modify_account: Allows changing user / account data (subject to the users permissions) :query_receivable_pud_update_channels: A special scope that grants only the minimum access required to use the `get_package_groups `_ API This is not needed if the application already uses the query_account scope :create_longterm_token: Allows a client to obtain a long term refresh token for itself. :create_service_tokens: Allows a client to obtain tokens on behalf of other clients. This is a highly privileged operation, therefore this scope will only be granted to trusted clients in rare cases. Please consult with pm_p-log@easterngraphics.com first if you think you will need this scope. :query_basic_organization_info: Allows querying a reduced set of organisation information for clients that don't have the query_account scope .. _api_oauth2_logout: Logout ------ For clients that are `pcon_session` clients it is recommended to perform a logout by redirecting to the logut page: https://login.pcon-solutions.com/logout. This will implictely revoke all tokens of clients assoicated with this pcon_session. The optional url parameter `next` can be used to redirect back to your application e.g.: `https://login.pcon-solutions.com/logout?next=https%3A%2F%2Fmyapp.example.com%2Flogged_out` will redirect back to `https://myapp.example.com/logged_out` Clients that do not participate in the `pcon_session` should instead simply revoke their tokens.