Table of Contents
FAPI 2.0 Message Signing profile is a security profile for Financial-grade APIs that extends FAPI 2.0 Security profile as its foundation. It mainly defines four categories of requirements:
This article focuses on the requirements for Signing Authorization Requests in FAPI 2.0 Message Signing profile and provides instruction on how to configure services and clients to make them comply with the requirements. Hereafter, we will refer this category of requirements as FAPI2 MS Auth Req .
FAPI2 MS Auth Req feature is available since Authlete 2.3
The below is a diagram that roughly describes Authorization Code Flow in FAPI2 MS Auth Req.
A client sends a request including a signed request object to the pushed authorization request endpoint of the authorization server to register authorization request parameters. FAPI2 MS Auth Req imposes some requirements on authorization request parameters such as response_type . It also requires the client to be authenticated at the endpoint with mutual TLS authentication or private_key_jwt . In this document, we use private_key_jwt for client authentication.
If the request is processed successfully, the pushed authorization request endpoint responds with a request_uri .
The client sends an authorization request including the request_uri to the authorization endpoint of the authorization server. This is done via the user agent.
If the request is processed successfully, the authorization endpoint responds with an authorization code and the user agent redirects to the client’s redirect URI.
The client sends a token request to the token endpoint of the authorization server with the authorization code. FAPI2 MS Auth Req requires the token endpoint to issue access tokens that are sender-constrained with mutual TLS or DPoP . In this document, we use DPoP as a sender-constrained access token mechanism. Note that private_key_jwt is also used for client authentication at the token endpoint.
If the request is processed successfully, the token endpoint responds with a sender-constrained access token.
The client sends a request to a resource endpoint with the access token along with the proof-of-possession for the access token.
Similar to what we do for FAPI 2.0 Security Profile, we have introduced a new scope attribute for “FAPI2 MS Auth Req”, which is defined as follows.
attribute key | attribute value |
---|---|
fapi2 | ms-authreq |
From this point forward, a scope associated with this attribute will be referred as a FAPI2 MS Auth Req scope .
Configure your service as follows to make it comply with FAPI2 MS Auth Req.
Property | Description |
---|---|
Supported Grant Types | Include AUTHORIZATION_CODE . |
Supported Response Types | Include CODE . |
Supported Service Profiles | Include FAPI . |
iss Response Parameter | Select Included . |
Token Endpoint URI | Set your authorization server’s token endpoint URI. |
Supported Client Authentication Methods | Select PRIVATE_KEY_JWT . |
nbf Claim | Select Required . |
Audience Validation | Select Perform . |
Access Token Signature Algorithm | NOTE: This configuration is only required if “JWT Access Token” is used.Select PS256 , ES256 or EdDSA . |
Supported Scopes | Include a FAPI2 MS Auth Req scope. |
JWK Set | NOTE: This configuration is only required if “JWK Set” is used.Set a JWK set containing required JWKs (e.g. JWT access token sign key). |
JWK Set Endpoint URI | NOTE: This configuration is only required if “JWK Set Endpoint URI” is used.Set a URI that starts with https . The URI needs to point to a JWK set containing required JWKs (e.g. JWT access token sign key). |
Configure your client as follows to make it comply with FAPI2 MS Auth Req.
Property | Description |
---|---|
Client Type | Select CONFIDENTIAL . |
Grant Types | Include AUTHORIZATION_CODE . |
Response Types | Include CODE . |
Redirect URIs | Create at least one redirect URI. |
Client Authentication Method | Select PRIVATE_KEY_JWT . |
Assertion Signature Algorithm | Select PS256 , ES256 or EdDSA . |
ID Token Signature Algorithm | Note: This configuration is only required if ID tokens are issued and signed.Select an encryption algorithm other than NONE . |
ID Token Encryption Algorithm | Note: This configuration is only required if ID tokens are issued and encrypted.Select an encryption algorithm other than RSA1_5 . |
JWK Set Content | NOTE: This configuration is only required if “JWK Set Content” is used.Set a JWK set containing required JWKs (e.g. client assertion sign key). |
JWK Set URI | NOTE: This configuration is only required if “JWK Set URI” is used.Set a URI that starts with https . The URI needs to point to a JWK set containing required JWKs (e.g. client assertion sign key). |
In this section, we simulate API calls that the authorization server makes against Authlete APIs in the context of Authorization Code Flow in FAPI2 MS Auth Req.
Suppose that a FAPI2 MS Auth Req compliant client sends a valid request to the pushed authorization request endpoint of authorization server in the context of Authorization Code Flow. According to 5.4.2. Requirements for Clients , the request would be like below.
POST /par HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
reuqest=eyJhbGci...
.eyJhdWQi...
.dUDwPyAk...
&client_id=2990629246
&client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=eyJhbGci...
.eyJzdWIi...
.BRwe9L6f...
The value of the “request” parameter is a signed JWT. The payload of the JWT is as follows.
{
"iss": "1716834948",
"response_type": "code",
"code_challenge_method": "S256",
"nonce": "aOLpUqqjMINQeclZ",
"client_id": "1716834948",
"aud": "https://server.example.com",
"nbf": 1701760807,
"scope": "myscope",
"redirect_uri": "https://client.example.com/cb",
"exp": 1701760867,
"jti": "kcvE4Tn",
"code_challenge": "pr2TmSd_rBnwn8a5Jxf5Sqd56z41o_y-as0_2-dDMpE"
}
Note details:
After the authorization server receives the request from the client, the authorization server calls Authlete /pushed_auth_req API including the received parameters. The following is a curl command that simulates a request from the authorization server to Authlete /pushed_auth_req API.
curl -s -X POST https://api.authlete.com/api/pushed_auth_req \
-u '20699248885:VR6lv6BbPx04p7D7vcx-7YM6OrHVLUQitahPyma6API' \
-H 'Content-type: application/json' \
-d '{
"parameters": "reuqest=eyJhbGci... .eyJhdWQi... .dUDwPyAk...&client_id=2990629246",
"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
"client_assertion": "eyJhbGci... .eyJzdWIi... .BRwe9L6f..."
}'
A successful response from the API contains a request URI. The response would look like below.
{
"resultCode": "A245001",
"resultMessage": "[A245001] Successfully registered a request object for client (2990629246), URI is urn:ietf:params:oauth:request_uri:H7XaM5FK2-RGcSRilYwe9FosTkk9XLMDZPEBA5uKsf8.",
"action": "CREATED",
"requestUri": "urn:ietf:params:oauth:request_uri:H7XaM5FK2-RGcSRilYwe9FosTkk9XLMDZPEBA5uKsf8",
"responseContent": "{
\"expires_in\": 60,
\"request_uri\": \"urn:ietf:params:oauth:request_uri:H7XaM5FK2-RGcSRilYwe9FosTkk9XLMDZPEBA5uKsf8\"
}"
}
The client sends an authorization request, including the request URI obtained in step 1, to the authorization endpoint of the authorization server. The request appears as below.
GET /authorization?client_id=2990629246&request_uri=urn:ietf:params:oauth:request_uri:H7XaM5FK2-RGcSRilYwe9FosTkk9XLMDZPEBA5uKsf8
HTTP/1.1
Host: server.example.com
After the authorization server receives the request from the client, the authorization sever calls Authlete /auth/authorization API. The following is a curl command that simulates a request from the authorization server to Authlete /auth/authorization API.
curl -s -X POST https://api.authlete.com/api/auth/authorization \
-u '20699248885:VR6lv6BbPx04p7D7vcx-7YM6OrHVLUQitahPyma6API' \
-H 'Content-type: application/json' \
-d '{
"parameters": "client_id=2990629246",
"request_uri": "urn:ietf:params:oauth:request_uri:H7XaM5FK2-RGcSRilYwe9FosTkk9XLMDZPEBA5uKsf8"
}'
A successful response from the API would be like below.
{
"type": "authorizationResponse",
"resultCode": "A004001",
"resultMessage": "[A004001] Authlete has successfully issued a ticket to the service (API Key = 2990629246) for the authorization request from the client (ID = 13446736418). [response_type=code, openid=false]",
"ticket": "CBKnPeMOf9xfv0sV-srVzbZv_dtFh01Zc0VkQ2nQKFg"
}
After the authorization server receives a successful response from /auth/authorization API, the end-user authorizes/denies the client in the browser. The authorization result is then conveyed to the authorization server and the authorization server calls Authlete /auth/authorization/issue API with the result. The following is a curl command that simulates a request from the authorization server to Authlete /auth/authorization/issue API.
curl -s -X POST https://api.authlete.com/api/auth/authorization/issue \
-u '20699248885:VR6lv6BbPx04p7D7vcx-7YM6OrHVLUQitahPyma6API' \
-H 'Content-type: application/json' \
-d '{
"ticket": "CBKnPeMOf9xfv0sV-srVzbZv_dtFh01Zc0VkQ2nQKFg",
"subject": "john",
"result": "AUTHORIZED"
}'
A successful response from the API would be like below.
{
"type": "authorizationIssueResponse",
"resultCode": "A040001",
"resultMessage": "[A040001] The authorization request was processed successfully.",
"authorizationCode": "smseP17uZwEg13HrB_Y24fnKn9nMFVBOE-hoDwtYy74",
...
}
The client sends a token request, including the authorization code obtained in step 3, to the token endpoint of the authorization server. The request would look like as below.
POST /token HTTP/1.1
Host: server.example.com
Content-Type: application/x-www-form-urlencoded
DPoP: eyJ0eXAi... .eyJqdGki... .codEOIUY...
client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer
&client_assertion=eyJhbGci... .eyJzdWIi... .BRwe9L6f...
&client_id=2990629246
&code=smseP17uZwEg13HrB_Y24fnKn9nMFVBOE-hoDwtYy74
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
&grant_type=authorization_code
&code_verifier=ErRt0wrt3cOlLe592l1J-m9ROi9x4riZuHGpl6-9d2I
Note details:
After the token endpoint receives a request from the client, the authorization server calls Authlete /auth/token API. The following is a curl command that simulates a request from the authorization server to Authlete /auth/token API.
curl -s -X POST https://api.authlete.com/auth/token \
-u '20699248885:VR6lv6BbPx04p7D7vcx-7YM6OrHVLUQitahPyma6API' \
-H 'Content-type: application/json' \
-d '{"parameters":"client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer&client_assertion=eyJraWQi... .eyJqdGki... .-Gn4X3d_...&client_id=13446736418&code=smseP17uZwEg13HrB_Y24fnKn9nMFVBOE-hoDwtYy74&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb&grant_type=authorization_code&code_verifier=ErRt0wrt3cOlLe592l1J-m9ROi9x4riZuHGpl6-9d2I",
"dpop":"eyJ0eXAi... .eyJqdGki... .codEOIUY..."}'
A successful response from the API would be like below.
{
"resultCode": "A050001",
"resultMessage": "[A050001] The token request (grant_type=authorization_code) was processed successfully.",
"accessToken": "7i9xPkbkKCmcmkZIvSGci5PKf4HO9TUAefwsABMrbTQ",
...
}
After completing all the steps above, the client gets an access token and can access a resource server’s endpoint with the access token like below.
GET /api/sample HTTP/1.1
Authorization: DPoP 7i9xPkbkKCmcmkZIvSGci5PKf4HO9TUAefwsABMrbTQ
DPoP: eyJ0eXAi...
Host: resource.example.com
Note that the client needs to present a DPoP proof JWT to the resource server’s endpoint along with the access token.
When the resource server receives the request from the client, it calls Authlete /auth/introspection API to verify the access token. The following is a curl command that simulates a request from the resource server to Authlete /auth/introspection API.
curl -s -X POST https://api.authlete.com/api/auth/introspection \
-u '20699248885:VR6lv6BbPx04p7D7vcx-7YM6OrHVLUQitahPyma6API' \
-H 'Content-type: application/json' \
-d '{
"token": "7i9xPkbkKCmcmkZIvSGci5PKf4HO9TUAefwsABMrbTQ",
"dpop": "eyJ0eXAi... .eyJqdGki... .codEOIUY...",
"htm": "GET",
"htu": "https://resource.example.com/api/sample"
}'
A successful response from the API would be like below.
{
"resultCode": "A056001",
"resultMessage": "[A056001] The access token is valid.",
"action": "OK",
...
}