OAuth2.0 client authentication
Introduction
When a client application wants to get an access token from Safewhere Identify, Safewhere Identify assumes that the client type of this client application is "confidential". As described in the specification, the client application must not use more than one authentication method in its requests. You need to establish the authentication method of the client application on Safewhere Identify using the Admin interface or REST API.
Discovery endpoint
The discovery endpoint returns a list of supported client authentication methods:
"token_endpoint_auth_methods_supported": [
"none",
"client_secret_basic",
"client_secret_post",
"private_key_jwt",
"tls_client_auth",
"self_signed_tls_client_auth"
]
Dynamic client registration endpoint
Please visit the Client metadata section for more details about supported keys:
Key name |
---|
token_endpoint_auth_method |
jwks |
jwks_uri |
Client authentication methods
None method
Setting up Safewhere Identify to use None
You must specify the None option on the OAuth2.0/OIDC application connection setting
Some notes for the None
option:
- The
None
option functions similarly to the OAuthTokenEndpointAuthenticationMethods=None flag. - Even with the
None
option chosen, theClient Credentials
,Bearer
, andToken Exchange
flows will still require a client_secret. - The
None
option is not applicable when the application type isWeb
(confidential) orUnspecified
. It is exclusively available forNative
andJavaScript
applications.
For the REST API, you can add two properties to the "configuration" connection JSON element: "tokenEndpointAuthenticationMethod" and "applicationType" (either Native
or JavaScript
)
{
"tokenEndpointAuthenticationMethod": "None",
"applicationType": "Native",
}
Client application
When a client application sends a token request, it includes the client ID in the request body.
POST https://#yourdomain/runtime/oauth2/token.idp
Content-Type: application/x-www-form-urlencoded
The following example, which exchanges a refresh token for an access token, sends a request without a secret:
Key | Value |
---|---|
grant_type | refresh_token |
refresh_token | CfDJ8Fycs0UIYjdK ... 7HO6bo97vAmQ1ONf2nayM |
client_id | test_client_id |
{
"grant_type": "refresh_token",
"refresh_token": "CfDJ8Fycs0UIYjdK ... 7HO6bo97vAmQ1ONf2nayM",
"client_id": "test_client_id"
}
If the request is valid, Safewhere Identify will return an access token.
client_secret_post method
Setting up Safewhere Identify to use client_secret_post
You must specify the ClientSecretPost option on the OAuth2.0/OIDC application connection setting
For the REST API, you can add a property named "tokenEndpointAuthenticationMethod" into the "configuration" connection JSON element.
{
"tokenEndpointAuthenticationMethod": "ClientSecretPost"
}
Client application
When a client application sends a token request, it includes the client ID and the client secret in the request body.
POST https://#yourdomain/runtime/oauth2/token.idp
Content-Type: application/x-www-form-urlencoded
The following example, which exchanges a refresh token for an access token, sends a request with a secret in the request body:
Key | Value |
---|---|
grant_type | refresh_token |
refresh_token | CfDJ8Fycs0UIYjdK ... 7HO6bo97vAmQ1ONf2nayM |
client_id | test_client_id |
client_secret | test_client_secret |
{
"grant_type": "refresh_token",
"refresh_token": "CfDJ8Fycs0UIYjdK ... 7HO6bo97vAmQ1ONf2nayM",
"client_id": "test_client_id",
"client_secret": "test_client_secret"
}
If the request is valid, Safewhere Identify will return an access token.
client_secret_basic method
Setting up Safewhere Identify to use client_secret_basic
You must specify the ClientSecretBasic option on the OAuth2.0/OIDC application connection setting
For the REST API, you can add a property named "tokenEndpointAuthenticationMethod" into the "configuration" connection JSON element.
{
"tokenEndpointAuthenticationMethod": "ClientSecretBasic"
}
Client application
A client application builds a string by concatenating a client ID, a colon, and a client secret.
{client_id}:{client_secret}
Next, it needs to base64-encode the string and put it in an Authorization header of a token request.
POST https://#yourdomain/runtime/oauth2/token.idp
Content-Type: application/x-www-form-urlencoded
Authorization: Basic b2F1dGgyX2NvZGVmbG93X3Jlc3RhcGlfdG9rZW5fNjUzMDI2M2YtZmM2NS1lMzA0LWM4OTUtY2NiZWM2N2I4NDk2Om9hdXRoMl9jb2RlZmxvd19yZXN0YXBpX3Rva2VuXzQ1dC94Z1RxOVBCYTN3PT0=
The following example, which exchanges a refresh token for an access token, sends a request with an Authorization header:
Key | Value |
---|---|
grant_type | refresh_token |
refresh_token | CfDJ8Fycs0UIY ... o97vAmQ1ONf2nayM |
{
"grant_type": "refresh_token",
"refresh_token": "CfDJ8Fycs0UIY ... o97vAmQ1ONf2nayM"
}
If the request is valid, Safewhere Identify will return an access token.
Private Key JWT method
Safewhere Identify allows you to use the private_key_jwt method to authenticate your clients.
Setting up Safewhere Identify to use private_key_jwt
You need to update the settings below:
- Token endpoint authentication method: set to PrivateKeyJwt
- Register the client's public key jwks to the setting Client's registered jkws which are used for verifying client_assertion or its jwks_uri to the setting: A client's uri from which Safewhere Identify can fetch its jkws that are used for verifying client_assertion. Please note that these 2 settings cannot be set at the same time. Only one of them can be used. Otherwise, the connection cannot be saved.
You can find the option on the OAuth2.0/OIDC application connection setting:
For the REST API, you can add a property named "clientJwks" or "clientJwksUri" / "tokenEndpointAuthenticationMethod" into its "configuration" connection JSON element.
{
"tokenEndpointAuthenticationMethod": "PrivateKeyJwt",
"clientJwks": "{\n \"keys\": [\n {\n \"kid\": \"PB_XNaQDXjt40zRE3lMnw5OqKC4\",\n \"use\": \"sig\",\n \"kty\": \"RSA\",\n \"alg\": \"RS256\",\n \"e\": \"AQAB\",\n \"n\": \"pRDtvsy1UVMG19LP7wnGNu38i03MOiQ5jHSyGOoich9dQWXN09g6iJiugFdriyAPT7BJ0heANFRaX54gaapxEfXGTsEkDu0Wm_rdwomJo7TMLrQZ_NZKNw5QqKCh1U7bASWSzbE1PgBK8k3EQrkphX37ymsVbm_iT53LIeB1hZTdv2aatTinZvmaxY7722fL5rOVTd0H6cR3L5Jnrkm9_OnXGN5Y7M3iNDjYCYeJFlGexR5TfGfhZ7jThtn008vXgFs1goQXewwH_xwhzuspbT3FY3XCLYQgdBjkyybR-lYJlTBgJyfBbgr-qCndRzTJ9vEoOoNKj-mW5hB4LB9ajw\",\n \"x5t\": \"PB_XNaQDXjt40zRE3lMnw5OqKC4\",\n \"x5c\": [ \"MIIDYTCCAsqgAwIBAgIQwFRaBL5xNbFGRPG2/1LnSDANBgkqhkiG9w0BAQsFADBJMRMwEQYKCZImiZPyLGQBGRYDbmV0MRkwFwYKCZImiZPyLGQBGRYJc2FmZXdoZXJlMRcwFQYDVQQDEw5TYWZld2hlcmUgQ0EgMjAeFw0wOTEyMzExNzAwMDBaFw0zMDEyMzAxNzAwMDBaMHoxCzAJBgNVBAYTAkRLMRMwEQYDVQQIEwpDb3BlbmhhZ2VuMRMwEQYDVQQHEwpEZXYgQnVua2VyMRIwEAYDVQQKEwlTYWZld2hlcmUxDDAKBgNVBAsTA0RldjEfMB0GA1UEAxMWSWRlbnRpZnlEZWZhdWx0U2lnbmluZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKUQ7b7MtVFTBtfSz+8Jxjbt/ItNzDokOYx0shjqInIfXUFlzdPYOoiYroBXa4sgD0+wSdIXgDRUWl+eIGmqcRH1xk7BJA7tFpv63cKJiaO0zC60GfzWSjcOUKigodVO2wElks2xNT4ASvJNxEK5KYV9+8prFW5v4k+dyyHgdYWU3b9mmrU4p2b5msWO+9tny+azlU3dB+nEdy+SZ65Jvfzp1xjeWOzN4jQ42AmHiRZRnsUeU3xn4We404bZ9NPL14BbNYKEF3sMB/8cIc7rKW09xWN1wi2EIHQY5Msm0fpWCZUwYCcnwW4K/qgp3Uc0yfbxKDqDSo/pluYQeCwfWo8CAwEAAaOBlDCBkTATBgNVHSUEDDAKBggrBgEFBQcDATB6BgNVHQEEczBxgBAFQDRik9fSAavzW0IEXV98oUswSTETMBEGCgmSJomT8ixkARkWA25ldDEZMBcGCgmSJomT8ixkARkWCXNhZmV3aGVyZTEXMBUGA1UEAxMOU2FmZXdoZXJlIENBIDKCEFml1D7IO163RfencPmdPmwwDQYJKoZIhvcNAQELBQADgYEANHyflZiSVAtmOBwfevURrRVTaRbzcBMi14+FrYIet2z22afRoY8jnJqcHN2w7z/gwn1MNPNYo0Bz3NL8tMXm2DNRle6E0EhcKB3979L6p8XvIkvZmZtDWy0WSQeAlz6R5BA5tp0vYmV/GkgUWWoHLQw5VIU/gYBDCdMkvtZrJrA=\" ]\n }\n ]\n}",
"clientJwksUri": "",
}
Note: The jwks_uri and jwks parameters MUST NOT be used together.
Client application
The client must send a request that contains the following parameters to the token endpoint when using the private_key_jwt method.
Parameter | Description |
---|---|
client_assertion_type | The value must be "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" |
client_assertion | A JWT that contains information about client authentication |
The JWT must be signed using an SHA-256 algorithm. It must contain the following required claim values and may contain the following optional claim values:
- iss: REQUIRED. The Issuer claim that MUST contain the client_id of the OAuth Client.
- sub: REQUIRED. The Subject claim that MUST contain the client_id of the OAuth Client.
- aud: REQUIRED. The Audience claim that identifies the Authorization Server as an intended audience. The Authorization Server MUST verify that it is an intended audience for the token. The Audience MUST be the URL of the Authorization Server's Token Endpoint.
- jti: REQUIRED. A unique identifier (JWT ID) for the token, which can be used to prevent reuse of the token. These tokens MUST only be used once, unless conditions for reuse were negotiated between the parties; any such negotiation is beyond the scope of this specification.
- exp: REQUIRED. Expiration time on or after which the ID Token MUST NOT be accepted for processing.
- iat: OPTIONAL. Time at which the JWT was issued.
Request URL:
POST https://#yourdomain/runtime/oauth2/token.idp
Content-Type: application/x-www-form-urlencoded
The following example, which exchanges an authorization code for an access token, sends a request with a client assertion type, a client assertion in the request body:
Name | Value |
---|---|
client_assertion_type | urn:ietf:params:oauth:client-assertion-type:jwt-bearer |
client_assertion | eyJhbGciOiJSUzI1NiIsImtpZCI6IlBCX1hOYVFEWGp0NDB6UkUzbE1udzVPcUtDNCIsIng1dCI6IlBCX1hOYVFEWGp0NDB6UkUzbE1udzVPcUtDNCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ3ZWJtdmNfY29kZWZsb3dfaWQiLCJhdWQiOiJodHRwczovL2lkZW50aWZ5djU5a2V5MS5zYWZld2hlcmUubG9jYWwvcnVudGltZS9vYXV0aDIvdG9rZW4uaWRwIiwiZXhwIjoxOTEyMTI5NTcxLCJqdGkiOiJkMGQ0YjY0Zi1lYmZmLTQ4OWQtYmU0Mi1lOTAxOGM3NmYwNjQiLCJuYmYiOjE1OTY1OTY3NzEsImlhdCI6MTU5NjU5Njc3MSwiaXNzIjoid2VibXZjX2NvZGVmbG93X2lkIn0.BIJZGRcGZpExnG92hwQo468yibex2vuK5M8Gfs8IN9SX0po2zdm3q9Cs8RkYvrIneiFev27h9nmznQJzYeBqgL45pjH7hhThRA5bEeonnneXXfBfsLz3_L08zc-RqSAEfucUaWIbLTLwq8L6mjz6Vmr5tmXOBMFu_iq-SQ-vF9YejZwwJ43tnsRCaWJiLgNAxgW9V4isV4W41XfQNq7I71JaM45EjpL3zi6wyxB9Jo2bJfLMiOfNEPzUB5uIXZf9llnUPmnHVNhOVrDN6GqogT-xUOz0GVjD_5tsCyY7iFJOwyogKIefnuDF80RrxUPwb6-g1RQmy5ipk4ELpL8v5A |
grant_type | authorization_code |
redirect_uri | http://localhost:62640/Home/CodeFlowCallback |
code | CfDJ8Fycs0UIYjdKtFPMj_-nsJgbZNXG-sT4 ... T10EQ7cVnm2OD_biMovjk6CKA4zC7jWfJNyzTbhEHx73UDnNCMrw |
{
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": "eyJhbGciOiJSUzI1NiIsImtpZCI6IlBCX1hOYVFEWGp0NDB6UkUzbE1udzVPcUtDNCIsIng1dCI6IlBCX1hOYVFEWGp0NDB6UkUzbE1udzVPcUtDNCIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ3ZWJtdmNfY29kZWZsb3dfaWQiLCJhdWQiOiJodHRwczovL2lkZW50aWZ5djU5a2V5MS5zYWZld2hlcmUubG9jYWwvcnVudGltZS9vYXV0aDIvdG9rZW4uaWRwIiwiZXhwIjoxOTEyMTI5NTcxLCJqdGkiOiJkMGQ0YjY0Zi1lYmZmLTQ4OWQtYmU0Mi1lOTAxOGM3NmYwNjQiLCJuYmYiOjE1OTY1OTY3NzEsImlhdCI6MTU5NjU5Njc3MSwiaXNzIjoid2VibXZjX2NvZGVmbG93X2lkIn0.BIJZGRcGZpExnG92hwQo468yibex2vuK5M8Gfs8IN9SX0po2zdm3q9Cs8RkYvrIneiFev27h9nmznQJzYeBqgL45pjH7hhThRA5bEeonnneXXfBfsLz3_L08zc-RqSAEfucUaWIbLTLwq8L6mjz6Vmr5tmXOBMFu_iq-SQ-vF9YejZwwJ43tnsRCaWJiLgNAxgW9V4isV4W41XfQNq7I71JaM45EjpL3zi6wyxB9Jo2bJfLMiOfNEPzUB5uIXZf9llnUPmnHVNhOVrDN6GqogT-xUOz0GVjD_5tsCyY7iFJOwyogKIefnuDF80RrxUPwb6-g1RQmy5ipk4ELpL8v5A",
"grant_type": "authorization_code",
"redirect_uri": "http://localhost:62640/Home/CodeFlowCallback",
"code": "CfDJ8Fycs0UIYjdKtFPMj_-nsJgbZNXG-sT4 ... T10EQ7cVnm2OD_biMovjk6CKA4zC7jWfJNyzTbhEHx73UDnNCMrw",
}
If the request is valid, Safewhere Identify will return an access_token.
tls_client_auth and self_signed_tls_client_auth method
Safewhere Identify allows you to use the Mutual-TLS Client Authentication method to authenticate your clients.
ASP.NET MVC Sample
You can use our web application sample to try the Client authentication out.
A couple of keys were added into the web.config:
<add key="IdentifyOauth2:AuthenticationType" value="private_key_jwt" />
<add key="IdentifyOauth2:ClientCertificate" value="3C1FD735A4035E3B78D33444DE5327C393AA282E" />
Given that you want to try the private_key_jwt method, you set the "IdentifyOauth2:AuthenticationType" setting to "private_key_jwt", generate a valid JWT and use the signing certificate's private key to sign the JWT.
You can use our jwks sample for configuring the connection.
Q&A
- Question: What Identify version supports the client authentication feature?
- Answer: The feature is supported from version 5.6.
- Question: A client application receives an error message about the authentication type error when it sends a request to the token endpoint, e.g the one below:
{
"error": "invalid_client",
"error_description": "Invalid setting: authentication type 'ClientSecretPost' is not supported for this client, please check the appropriate settings again."
}
- Answer: The client application uses the client authentication "ClientSecretPost", but the "Token endpoint authentication method" setting of the OAuth2.0/OIDC connection has specified a different one. You can reset the setting to use the correct option, which in this example is "ClientSecretPost".
- Question: Are the previous configured OAuth2.0/OIDC applications on an Identify instance broken after being upgraded to a new version?
- Answer: Accessing existing OAuth2.0/OIDC applications is not broken after an upgrade. However, you should contact the owners of the client applications to get information about their in-use client authentication method and update it on the setting "Token endpoint authentication method" of the corresponding OAuth2.0/OIDC connection.