Table of Contents
This document describes how to evaluate FAPI-compliant authorization flow and API request using an an Authlete service, that has been configured with settings described in Financial-grade API (FAPI) Basics (hereinafter “FAPI Basics”), and other components including Authlete’s reference implementations.
Before doing this, you are expected to have knowledge of OpenID Connect and Authlete by running through the following tutorial.
You also need to have an Authlete service that has been configured with settings in accordance with FAPI Basics below. Run the instructions (A complete example walk through) in the document to make sure that your Authlete service works properly.
The following software components are used in this tutorial. Prepare your lab environment that can execute them.
In this section, we will cover the following tasks:
The diagram below illustrates components configured in this section. A Web browser and curl send requests to an authorization server (java-oauth-server) whose endpoint is http://localhost:8080.
We will download and configure java-oauth-server. Detailed instructions are described in its document.
Download java-oauth-server using git
command.
$ git clone https://github.com/authlete/java-oauth-server.git
Edit the following entries in its configuration file, authlete.properties
.
Put the API key and the secret of your Authlete service that has been configured in accordance with FAPI Basics.
service.api_key = <your API key e.g. 1450...0338>
service.api_secret = <your API key e.g. VEIl...0cEs>
Start java-oauth-server using mvn
command.
$ mvn jetty:run
Connect to http://localhost:8080 using a Web browser and the following page should be displayed.
Generate a request object in accordance with instructions in FAPI Basics and craft an authorization request using the object. The following values are used in this tutorial.
client_id
(1756...3766
) with yours that has been automatically generated during FAPI Basics){
"redirect_uri":"https://client.example.org/cb/example.com",
"response_type":"code id_token",
"client_id":"1756...3766",
"scope":"openid payment",
"exp":15549730000,
"aud":"https://as.example.com",
"claims":{
"id_token":{
"acr":{
"essential":true,
"values":["urn:example:psd2:sca"]
}
}
},
"nonce":"n-0S6_WzA2Mj"
eyJr...YifQ.ewoi...iCn0.ztl2...tjAA
client_id
(1756...3766
) and request
(eyJr...YifQ.ewoi...iCn0.ztl2...tjAA
) with yours determined above)http://as.example.com:8080/api/authorization
?redirect_uri=https://client.example.org/cb/example.com
&scope=openid+payment
&response_type=code+id_token
&client_id=1756...3766
&nonce=n-0S6_WzA2Mj
&request=eyJr...YifQ.ewoi...iCn0.ztl2...tjAA
Enter the crafted request string (URL) to your Web browser’s location field.
An authorization page should be displayed.
Enter john
/ john
to Login ID / Password fields and click Authorize button.
Your Web browser will attempt (and fail) to connect https://client.example.org/cb/example.com/#code=...
and show an error page stating that the host client.example.org
doesn’t exist.
Copy the URL of the error page like below.
https://client.example.org/cb/example.com#code=0Io2....sdkQ&id_token=eyJr...YifQ.eyJz...aiJ9.-EPu...Dkkw
Extract code
parameter in the URL.
code=0Io2...sdkQ
Let’s craft a token request that contains the value of code
(0Io2...sdkQ
for example)
and send it to java-oauth-server’s token endpoint (/api/token).
In this section, we will try to do client authentication using client_id
/ client_secret
as follows.
Replace values of these parameters with yours that have been automatically generated during FAPI Basics.
$ curl -s -X POST http://localhost:8080/api/token \
-u '1756...3766:EXE7...UxHg' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'redirect_uri=https://client.example.org/cb/example.com' \
--data-urlencode 'code=0Io2...sdkQ'
You will receive a token response like this:
{
"error_description": "[A244308] Because the feature of certificate-bound
access tokens is enabled, the client must establish a mutual TLS connection
to the token endpoint.",
"error": "invalid_request",
"error_uri": "https://docs.authlete.com/#A244308"
}
That means:
curl
command in this tutorial) and java-oauth-server"error_description"
and "error_uri"
.
You can omit them by configuring Authlete service settings.
See an article in Authlete Knowledge Base for details.
In the next section, we will add a reverse proxy to accept client certificates from clients to solve the error.
In this section, we will cover the following tasks:
The diagram below illustrates components configured in this section. In the previous section, both Web browsers and clients connect directly to java-oauth-server (http://localhost:8080). The destination will be switched to Apache (https://as.example.com:8443) that resides in front of the server as a reverse proxy. On the client side, curl will attempt to connect to Apache using a client certificate to get authenticated.
Add the following entry to /etc/hosts
so that both Web browsers and clients can find Apache to be installed in your lab environment, using as.example.com
as FQDN.
127.0.0.1 as.example.com
Install Apache in your lab environment.
$ brew install httpd
This tutorial uses /usr/local/etc/httpd
directory as the primary location of Apache’s configuration files.
Create an RSA private key and a public key certificate for Apache, using openssl
command.
$ openssl req -x509 -newkey rsa:2048 \
-keyout server.key -out server.crt
-days 3650 -sha256 -nodes \
-subj '/C=JP/ST=Tokyo/L=Chiyoda-ku/O=Server/CN=as.example.com'
Generating a 2048 bit RSA private key
..........................+++
....+++
writing new private key to 'server.key'
-----
Two files, server.key
(a private key) and server.crt
(a public key certificate) are created.
Deploy these two files to arbitrary location in your lab environment.
This tutorial copies them under /usr/local/etc/httpd
directory.
$ sudo cp -p server.key server.crt /usr/local/etc/httpd/.
Password:
We will configure basic Apache settings to:
Actual changes to the configuration file, httpd.conf
are as follows.
TLS related settings are to be included from another file (extra/httpd-ssl.conf
).
$ diff /usr/local/etc/httpd/httpd.conf.orig \
/usr/local/etc/httpd/httpd.conf
52c52
< Listen 8080
---
> #Listen 8080
92c92
< #LoadModule socache_shmcb_module lib/httpd/modules/mod_socache_shmcb.so
---
> LoadModule socache_shmcb_module lib/httpd/modules/mod_socache_shmcb.so
131c131
< #LoadModule proxy_module lib/httpd/modules/mod_proxy.so
---
> LoadModule proxy_module lib/httpd/modules/mod_proxy.so
134c134
< #LoadModule proxy_http_module lib/httpd/modules/mod_proxy_http.so
---
> LoadModule proxy_http_module lib/httpd/modules/mod_proxy_http.so
150c150
< #LoadModule ssl_module lib/httpd/modules/mod_ssl.so
---
> LoadModule ssl_module lib/httpd/modules/mod_ssl.so
524c524
< #Include /usr/local/etc/httpd/extra/httpd-ssl.conf
---
> Include /usr/local/etc/httpd/extra/httpd-ssl.conf
In this tutorial, we configure TLS and reverse proxy settings to:
Changes to the configuration file, extra/httpd-ssl.conf
are as follows.
$ diff /usr/local/etc/httpd/extra/httpd-ssl.conf.orig \
/usr/local/etc/httpd/extra/httpd-ssl.conf
125c125
< ServerName www.example.com:8443
---
> ServerName as.example.com:8443
289a290,302
> SSLEngine on
> SSLProtocol TLSv1.2
> SSLCipherSuite -ALL:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256
> SSLCertificateKeyFile "/usr/local/etc/httpd/server.key"
> SSLCACertificateFile "/usr/local/etc/httpd/server.crt"
> SSLVerifyClient optional_no_ca
> SSLOptions +StdEnvVars +ExportCertData
> SSLCompression off
> RequestHeader set X-Ssl-Cipher "%{SSL_CIPHER}e" env=SSL_CIPHER
> RequestHeader set X-Ssl-Cert "%{SSL_CLIENT_CERT}e" env=SSL_CLIENT_CERT
> ProxyPreserveHost on
> ProxyPass "/" "http://localhost:8080/"
> ProxyPassReverse "/" "http://localhost:8080/"
Start the Apache using apachectl
command.
$ apachectl start
Once it’s started, connect to https://as.example.com:8443 using your Web browser and confirm if the content is the same as http://localhost:8080, the top page of java-oauth-server.
In the next section, we wlll prepare a private key and a public key certificate for a client (curl) that makes a token request.
Execute openssl
command as follows to create a private key and a public key certificcate.
$ openssl req -x509 -newkey rsa:2048 \
-keyout client.key -out client.crt
-days 3650 -sha256 -nodes \
-subj '/C=JP/ST=Tokyo/L=Chiyoda-ku/O=Server/CN=client.example.org'
Generating a 2048 bit RSA private key
..........................+++
....+++
writing new private key to 'client.key'
-----
Two files, client.key
(a private key) and client.crt
(a public key certificate) are created.
We will use them to make token requests with curl.
Make an authorization request in the same way as Executing FAPI authorization flow (1).
Extract a value of code
parameter from an authorization response. The value in this tutorial is as follows.
7Y5h...zp_4
Craft a token request and send it to the token endpoint of java-oauth-server (/api/token). The different parts from the previous example (Executing FAPI authorization flow (1)) are:
https://as.example.com:8443
instead of http://localhost:8080
client.key
) and the public key certificate (client.crt
) instead of client_secret
Thus the curl
command to be executed is like below.
(replace the values of client_id
and code
with appropriate ones in your lab environment)
$ curl --insecure -X POST https://as.example.com:8443/api/token \
--key client.key --cert client.crt \
--data-urlencode 'client_id=1756...3766' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'redirect_uri=https://client.example.org/cb/example.com' \
--data-urlencode 'code=7Y5h...zp_4'
You should receive a token response like below.
{
"access_token": "nbN3...LAU8",
"refresh_token": "SWUu...V8_w",
"scope": "openid payment",
"id_token": "eyJr...YifQ.eyJz...qIn0.GPJr...STPQ",
"token_type": "Bearer",
"expires_in": 86400
}
Now you have successfully got an access token (nbN3...LAU8
for example) through mutual TLS connection. In the backstage, Authlete has made the access token bound to the client certificate.
In the next section, we will attempt to make an API request with an access token to a resource server.
In this section, we will cover the following tasks:
The diagram below illustrates components configured in this section.
We will download and configure java-resource-server. Instructions are described in its document.
Download java-resource-server using git
command.
$ git clone https://github.com/authlete/java-resource-server.git
Edit the following entries in its configuration file, authlete.properties
.
Put the API key and the secret that are
the same values as specified for java-oauth-server.
service.api_key = <your API key e.g. 1450...0338>
service.api_secret = <your API key e.g. VEIl...0cEs>
Start java-resource-server using mvn
command.
$ mvn jetty:run
Connect to http://localhost:8081 using a Web browser and the following page should be displayed.
Let’s try to make an API request with an access token to “Country Endpoint” of java-resource-server, using curl
command.
The access token can be obtained by doing the flow described in Executing FAPI authorization flow (2). In this tutorial, the following value is used.
6Ivp...LiM4
Make a request with the access token specified in Authorization
header.
The examples below show the request and the subsequent response.
-v
option is added to curl
command so that it can enable verbose output especially header information.
$ curl -v -X GET http://localhost:8081/api/country/JP \
-H 'Authorization: Bearer 6Ivp...LiM4'
...
> GET /api/country/JP HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.64.1
> Accept: */*
> Authorization: Bearer 6Ivp...LiM4
>
< HTTP/1.1 401 Unauthorized
< Date: Mon, 18 May 2020 02:22:32 GMT
< Cache-Control: no-store, no-transform
< Pragma: no-cache
< WWW-Authenticate: Bearer error="invalid_token",
error_description="[A065304] The client failed to present
a certificate and the access token is MTLS bound.",
error_uri="https://docs.authlete.com/#A065304"
< Content-Length: 0
< Server: Jetty(9.3.7.v20160115)
...
That response means:
curl
command) and java-resource-serverIn the next section, we will configure additional settings for the reverse proxy.
In this section, we will cover the following tasks that are basically the same as the settings for java-oauth-server done in the former section:
The diagram below illustrates components configured in this section. curl will attempt to connect to Apache (https://rs.example.com:8443) using a client certificate to get authenticated.
Modify the entry that has been added to /etc/hosts
during Configuring a reverse proxy (1) so that curl can connect to Apache using rs.example.com
.
127.0.0.1 as.example.com rs.example.com
Add the following entries to the extra/httpd-ssl.conf
file.
These settings, the same as Configuring a reverse proxy (1) except the server name and destinations of the reverse proxy, are to:
The additional entries to the configuration file, extra/httpd-ssl.conf
are as follows.
<VirtualHost _default_:8443>
DocumentRoot "/usr/local/var/www"
ServerName rs.example.com:8443
ServerAdmin you@example.com
ErrorLog "/usr/local/var/log/httpd/error_log"
TransferLog "/usr/local/var/log/httpd/access_log"
SSLEngine on
SSLProtocol TLSv1.2
SSLCipherSuite -ALL:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256
SSLCertificateKeyFile "/usr/local/etc/httpd/server.key"
SSLCertificateFile "/usr/local/etc/httpd/server.crt"
SSLCACertificateFile "/usr/local/etc/httpd/server.crt"
SSLVerifyClient optional_no_ca
SSLOptions +StdEnvVars +ExportCertData
SSLCompression off
RequestHeader set X-Ssl-Cipher "%{SSL_CIPHER}e" env=SSL_CIPHER
RequestHeader set X-Ssl-Cert "%{SSL_CLIENT_CERT}e" env=SSL_CLIENT_CERT
ProxyPreserveHost on
ProxyPass "/" "http://localhost:8081/"
ProxyPassReverse "/" "http://localhost:8081/"
</VirtualHost>
Stop and start the Apache using apachectl
command.
$ apachectl stop && apachectl start
After the restart, connect to https://rs.example.com:8443 using your Web browser and confirm if the content is the same as http://localhost:8081, the top page of java-resource-server.
Make an API request using curl
command in the same way as Executing an API request (1).
The access token can be obtained by doing the flow described in Executing FAPI authorization flow (2). In this tutorial, the following value is used.
6Ivp...LiM4
Make a request with the access token specified in Authorization
header.
The different parts from the previous example (Executing an API request (1)) are:
https://rs.example.com:8443
instead of http://localhost:8081
client.key
) and the public key certificate (client.crt
) in addition to the access tokenThus the curl
command to be executed is like below.
$ curl -v -X GET http://localhost:8081/api/country/JP \
-H 'Authorization: Bearer 6Ivp...LiM4' \
--key client.key --cert client.crt --insecure
...
You should receive a successful API response like below.
{
"name": "Japan",
"alpha2": "JP",
"alpha3": "JPN",
"numeric": 392,
"currency": "JPY"
}
It means that:
In this tutorial, we confirmed FAPI-compliant authorization flow and API request using a FAPI-enabled Authlete service, reference implementations (java-oauth-server and java-resource-server) and a reverse proxy.