AVAILABLE SINCE 15.3 updated in version 17.2
Pricefx supports OAuth 2.0 authorization and has implemented token endpoints according to https://datatracker.ietf.org/doc/html/rfc6749#section-6.
The partition acts as the OAuth 2.0 authorization server. It supports the Authorization Code Grant flow only. Dynamic Client Registration is not supported, so an administrator registers each client manually.
Implementations by Version
Pricefx has two implementations. They differ in where you register the clients and in what the client must send.
|
Version |
Client registration |
Described in |
|---|---|---|
|
17.2 and later |
OAuth Administration page. Client secrets are stored securely. |
|
|
15.3 to 17.1 |
|
oauthConfiguration Application Property (Version 17.1 and Earlier) |
In version 17.2, partitions still use the oauthConfiguration application property by default. The partition uses the clients from the OAuth Administration page only after Pricefx switches it to the new implementation. Until then, the section for version 17.1 and earlier applies.
OAuth Client Administration (Version 17.2 and Later)
You register the client on the OAuth Administration page. Give the client developer the Client ID, a client secret, and the Redirect URL.
This implementation has these rules:
-
Every client authenticates with a client secret. Public clients without a secret are not supported.
-
PKCE with the
S256method is required, as defined in RFC 7636. -
Scopes are not supported. The access token has exactly the permissions of the user who gave consent.
Endpoints
|
Endpoint |
URL |
|---|---|
|
Authorization |
|
|
Token |
|
Authorization Request
The client sends the user to the authorization endpoint with these parameters, as defined in RFC 6749, section 4.1.1:
|
Parameter |
Value |
|---|---|
|
|
|
|
|
The Client ID from the OAuth Administration page. It is a UUID. |
|
|
The Redirect URL from the OAuth Administration page. The value must match exactly. |
|
|
Required. The partition returns the value unchanged. |
|
|
The Base64url-encoded SHA-256 hash of the code verifier. It has 43 characters. |
|
|
|
|
|
Omit it or leave it empty. |
Example of an authorization request URL:
https://<instance base URL>/pricefx/<partition>/oauth/authorize?response_type=code&client_id=<Client ID>&redirect_uri=http%3A%2F%2Flocalhost%3A9876%2Fcallback&state=<state>&code_challenge=<code challenge>&code_challenge_method=S256
The user signs in and grants consent. The partition then redirects the user to the redirect_uri with the code and state parameters.
The partition handles errors in two ways:
-
If
client_idis missing, unknown or not a UUID, or ifredirect_uridoes not match, the partition returns HTTP 400. It does not redirect the user. -
For all other errors, the partition redirects the user to the
redirect_uriwith theerroranderror_descriptionparameters, as defined in RFC 6749, section 4.1.2.1.
The code is valid for 1 minute, and the client can use it only once. If the client sends the same code again within 5 minutes, the partition rejects it with invalid_grant. The partition also revokes the grant, so the access tokens issued for that code stop working.
Token Request
The client exchanges the code for tokens with a POST request to the token endpoint, as defined in RFC 6749, section 4.1.3. The request body contains these form parameters:
-
grant_type=authorization_code -
code– the code from the authorization response -
redirect_uri– the same value as in the authorization request -
code_verifier– the PKCE code verifier
The client authenticates in one of these ways:
-
In the HTTP
Authorizationheader, with Basic authentication (client_id:client_secret). -
With the
client_idandclient_secretform parameters in the request body.
Example of a token request:
curl -X POST "https://<instance base URL>/pricefx/<partition>/oauth/token" \
-u "<Client ID>:<client secret>" \
-d "grant_type=authorization_code" \
-d "code=<code>" \
-d "redirect_uri=http://localhost:9876/callback" \
-d "code_verifier=<code verifier>"
The response looks similar to this one:
{
"access_token": "eyJhbGciOi ....",
"token_type": "bearer",
"expires_in": 1800,
"refresh_token": "rt_ ...."
}
The expires_in value is the Token TTL of the client in seconds. The default is 1800 (30 minutes). An access token never outlives its grant. When the grant reaches its Absolute Refresh Token TTL sooner, expires_in is shorter than the Token TTL.
Refresh the Access Token
To get a new access token, the client sends a POST request to the token endpoint with these form parameters and the same client authentication:
-
grant_type=refresh_token -
refresh_token– the refresh token from the token response
The response contains a new access token. The refresh token stays the same: the partition does not issue a new one.
The refresh token is valid as long as its grant. The grant is the consent that the user gave to the client. Two settings of the client limit the grant:
-
Idle Refresh Token TTL – The grant expires when the client does not use it for this time. Each token refresh and each API call with an access token counts as use.
-
Absolute Refresh Token TTL – The grant expires this time after the client received its first tokens, even if the client uses it regularly.
When the grant expires, the user must sign in and give consent again.
The partition rejects the refresh request in these cases:
|
Case |
Error |
|---|---|
|
The |
|
|
The client secret is disabled, or the client is disabled or deleted. |
|
|
The grant has expired. |
|
|
The user who gave consent is deactivated. |
|
Use the Access Token
The access token is a JWT. The client sends it in the HTTP Authorization header:
Authorization: Bearer <access token>
The access token contains these claims:
|
Claim |
Value |
|---|---|
|
|
The issuer: |
|
|
The audience. It is the same URL as |
|
|
The ID of the user who gave consent. |
|
|
The time when the partition issued the token. |
|
|
The time when the token expires. |
|
|
A unique ID of the token. |
|
|
|
|
|
The partition name. |
|
|
The Client ID. |
|
|
The ID of the grant. |
The partition returns HTTP 401 when the access token expires. It also rejects the token immediately when the grant expires, when an administrator disables or deletes the client, or when the user is deactivated. For details, see OAuth Administration.
oauthConfiguration Application Property (Version 17.1 and Earlier)
Up to version 17.1, you register clients in the oauthConfiguration application property. In version 17.2, this configuration applies until Pricefx switches the partition to the new implementation.
This feature is currently experimental and subject to change, in particular
-
Reducing permission scopes and to allowing for a secret to be used are currently unsupported
-
From version 17.2, the OAuth Administration page replaces the application property.
We do support PKCE (as per https://datatracker.ietf.org/doc/html/rfc7636).
Client Registration and Prerequisites Setup
In order to use OAuth 2.0 a client with its specific client_id needs to be defined. This is done in a new application property called oauthConfiguration. Multiple clients can be registered.
The configuration details are as follows:
{
"knownClients" : {
"client1_full_profile": {
"redirect_uri": "http://localhost:8000/callback",
"samlProfile": "PFXAZURE",
"token_expiry": 7200,
"client_description": "Some reasonably short text. Like a label"
},
"client2_minimal_profile": {
"redirect_uri": "http://localhost:8000/callback",
}
}
}
-
The
client1_full_profileandclient2_minimal_profileare not fixed strings but are theclient_idvalues as they are sent by the OAuth 2.0 client and need to be adjusted accordingly. If the client sends aclient_idthat is not configured the flow will not work. As a minimum theredirect_urineeds to be configured as it will be sent by the client. -
samlProfile: If configured and non-empty, the user authentication will go through the named SSO SAML auth flow (DEFAULT may be used if there is only one configured). Otherwise the app will show a login page. -
token_expiry: Lifetime of the access token in seconds. If omitted, the default value is 7200. -
client_description: Text that is shown on the consent screen to describe the requesting client. If blank,client_idis shown.
API Endpoints
The URL scheme of both endpoints is:
https://<instance base URL>/pricefx/<partition>/oauth/<keyword>
oauth/authorize
This endpoint implements the https://datatracker.ietf.org/doc/html/rfc6749#section-3.1 authorization endpoint per OAuth 2.0 specification and requires the parameters as defined here: https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.1. At the end of the flow it will send a code value back to/via the redirection URL specified in the client’s config & initial request (as they need to be the same).
The code has to be consumed within 10 minutes and can be used only once!
Example of an authorization request URL:
https://<instance base URL>/pricefx/<partition>/oauth/authorize?response_type=code&client_id=client2_minimal_profile&redirect_uri=http%3A%2F%2Fredirecthost%2Foauth%2Fcallback
oauth/token
This endpoint implements the https://datatracker.ietf.org/doc/html/rfc6749#section-4.1.3 token endpoint per OAuth 2.0 specification.
The client must send client_id as a form parameter, also when it uses Basic authentication.
Example of a token request URL:
https://<instance base URL>/pricefx/<partition>/oauth/token?grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
The response will look similar to this one:
{
"access_token":"2YotnFZFEjr1zCsicMWpAA .... ",
"token_type":"bearer",
"expires_in":7200,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA ...."
}
There are some implementation specifics regarding the tokens:
The access_token will be a valid JWT token for that instance/partition for that user with a lifetime of 7200 seconds in this case. It can be used in the regular ways (e.g., as Cookie) but also newly in the standard “bearer” mode, i.e., as part of an HTTP Authorization header that looks like:
Authorization: bearer <token value here>
The refresh_token is also a valid (=signed) JWT token, however with a longer (currently unlimited but to-be-reviewed) lifetime. It carries a new type field that earmarks it as a refresh token. Hence it CANNOT be used directly as auth credential like the access token, but only as credential in the oauth/token request using the refresh_token scenario.