> ## Documentation Index
> Fetch the complete documentation index at: https://developers.authlete.com/llms.txt
> Use this file to discover all available pages before exploring further.

# FAPI Basics Supplement: Integration with Reference Implementations

> Financial-grade API (FAPI) Basics を通じて設定した Authlete に、リファレンス実装を統合し、動作を確認するチュートリアルです。

# はじめに

本書では、チュートリアル「Financial-grade API Basics」(以下 "FAPI Basics") の設定を行った Authlete サービスにリファレンス実装を統合し、
FAPI 準拠の認可フローと API リクエストの動作を確認します。

<img src="https://mintcdn.com/authlete/g-UM9YXVfm3jeKy0/protocols-and-flows/compliance-profiles/fapi_with_ref_impl_ja.svg?fit=max&auto=format&n=g-UM9YXVfm3jeKy0&q=85&s=0e1685a5182ae5bddb95927568f2f71c" alt="" width="712" height="371" data-path="protocols-and-flows/compliance-profiles/fapi_with_ref_impl_ja.svg" />

# 前提条件

手順の実施にあたっては、以下のチュートリアルの実施とナレッジベース記事の通読を行い、 OpenID Connect と Authlete に関する基本的な理解を有していることが必須です。

* [Authlete API チュートリアル: OIDC Basics](/ja/get-started/quickstarts/oidc-basics)
* [FAPI の機能を利用する](/ja/protocols-and-flows/compliance-profiles/how-to-use-fapi-feature)

また、以下のチュートリアル (FAPI Basics) の手順に従って、
Authlete が設定されている必要があります。
とくに、設定した環境が[「設定完了後の実行例」](/ja/protocols-and-flows/compliance-profiles/fapi-basics)の記述通りに動作することを確認してください。

* [Authlete API チュートリアル: Financial-grade API Basics](/ja/protocols-and-flows/compliance-profiles/fapi-basics)

本チュートリアルでは、動作確認に以下のソフトウェアを用います。
これらを実行可能な環境をご用意ください。

* チュートリアル実施に必須
  * [authlete/java-oauth-server](https://github.com/authlete/java-oauth-server/): 認可サーバーのリファレンス実装
  * [authlete/java-resource-server](https://github.com/authlete/java-resource-server/): リソースサーバーのリファレンス実装
* 同等の機能を有する別のソフトウェアにて代替も可能
  * [Apache HTTP Server](https://httpd.apache.org/) (以下 Apache): 認可サーバーおよびリソースサーバーのリバースプロキシー
  * [curl](https://curl.haxx.se/): API クライアント
  * [OpenSSL](https://www.openssl.org/): 秘密鍵・公開鍵証明書の生成

# 認可サーバーの設定

本セクションでは以下の作業を行います。

* java-oauth-server の導入
* 接続テスト

設定後の構成は以下の図の通りです。
Web ブラウザと curl は、それぞれ認可リクエスト・トークンリクエストを、
認可サーバーである java-oauth-server ([http://localhost:8080](http://localhost:8080)) に送信します。

<img src="https://mintcdn.com/authlete/g-UM9YXVfm3jeKy0/protocols-and-flows/compliance-profiles/java-oauth-server_01.svg?fit=max&auto=format&n=g-UM9YXVfm3jeKy0&q=85&s=f35fcc0c1258afa6e9f030da241a4d4f" alt="" width="712" height="371" data-path="protocols-and-flows/compliance-profiles/java-oauth-server_01.svg" />

## java-oauth-server の設定

[java-oauth-server のドキュメント](https://github.com/authlete/java-oauth-server#how-to-run)に従い、ダウンロードと設定を行います。

### ダウンロード

`git` コマンドを用いて java-oauth-server をダウンロードします。

```shell theme={null}
$ git clone https://github.com/authlete/java-oauth-server.git
```

### 設定

設定ファイル `authlete.properties` の以下の行を編集します。
FAPI Basics の設定が済んでいる Authlete サービスの、API キーと API シークレットを指定してください。

```shell theme={null}
service.api_key = <your API key e.g. 1450...0338>
service.api_secret = <your API key e.g. VEIl...0cEs>
```

### 起動

`mvn` コマンドを用いて java-oauth-server を起動します。

```shell theme={null}
$ mvn jetty:run
```

### 動作確認

Web ブラウザから [http://localhost:8080](http://localhost:8080) にアクセスし、以下のページが表示されることを確認します。

<img src="https://mintcdn.com/authlete/g-UM9YXVfm3jeKy0/protocols-and-flows/compliance-profiles/java-oauth-server_02.png?fit=max&auto=format&n=g-UM9YXVfm3jeKy0&q=85&s=030c465f3742a5603fa0d0e43d2e8823" alt="" width="1434" height="1640" data-path="protocols-and-flows/compliance-profiles/java-oauth-server_02.png" />

## FAPI 認可フローの実行 (1)

[FAPI Basics チュートリアルの手順](/ja/protocols-and-flows/compliance-profiles/fapi-basics)に従いリクエストオブジェクトを作成し、認可リクエストを組み立てます。本チュートリアルにて用いている内容は以下の通りです。

* ペイロード（`client_id` の値 (`1756...3766`) を [FAPI Basics にて自動生成された値](/ja/protocols-and-flows/compliance-profiles/fapi-basics)に変更してください）

```json theme={null}
{
"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"
```

* Signed JWT（[FAPI Basics にて生成した署名鍵](/ja/protocols-and-flows/compliance-profiles/fapi-basics)を用いてください）

```text theme={null}
eyJr...YifQ.ewoi...iCn0.ztl2...tjAA
```

* 認可リクエスト（`client_id` と `request` パラメーターの値
  (それぞれ `1756...3766`, `eyJr...YifQ.ewoi...iCn0.ztl2...tjAA`)
  を適宜変更してください）

```shell theme={null}
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
```

生成した認可リクエストの URL を、Web ブラウザのロケーションに入力・送信します。

<img src="https://mintcdn.com/authlete/g-UM9YXVfm3jeKy0/protocols-and-flows/compliance-profiles/java-oauth-server_03.png?fit=max&auto=format&n=g-UM9YXVfm3jeKy0&q=85&s=e228a93f3fa2a3e1bd15b1f7901cb7fe" alt="" width="2522" height="112" data-path="protocols-and-flows/compliance-profiles/java-oauth-server_03.png" />

認可ページが表示されます。
Login ID / Password に、それぞれ `john` / `john` と入力し、Authorize ボタンをクリックします。

<img src="https://mintcdn.com/authlete/g-UM9YXVfm3jeKy0/protocols-and-flows/compliance-profiles/java-oauth-server_04.png?fit=max&auto=format&n=g-UM9YXVfm3jeKy0&q=85&s=8ecc2abec6137b589236a6492c82ce39" alt="" width="998" height="1516" data-path="protocols-and-flows/compliance-profiles/java-oauth-server_04.png" />

`https://client.example.org/cb/example.com/#code=...` にリダイレクトされます。しかし、
ホスト `client.example.org` は存在しないため、Web ブラウザはエラーページを表示します。

<img src="https://mintcdn.com/authlete/g-UM9YXVfm3jeKy0/protocols-and-flows/compliance-profiles/java-oauth-server_05_ja.png?fit=max&auto=format&n=g-UM9YXVfm3jeKy0&q=85&s=3f0e3e6facb5cb5eca0c2fde45299b22" alt="" width="1006" height="932" data-path="protocols-and-flows/compliance-profiles/java-oauth-server_05_ja.png" />

### 認可レスポンス

Web ブラウザの表示したエラーページの URL をコピーします。本チュートリアルでは以下の内容になります。

```html theme={null}
https://client.example.org/cb/example.com#code=0Io2....sdkQ&id_token=eyJr...YifQ.eyJz...aiJ9.-EPu...Dkkw
```

この URL から `code` パラメーターを取り出します。

```shell theme={null}
code=0Io2...sdkQ
```

### トークンリクエスト

先に得た `code` の値を含むトークンリクエストを組み立て、java-oauth-server のトークンエンドポイント (/api/token) に送信します。
ここではまず、`client_id` / `client_secret` によるクライアント認証を試みます。
本チュートリアルでの各値は `0Io2...sdkQ`, `1756...3766`, `EXE7...UxHg`
となっていますが、適宜変更してください。

<div class="alert alert-info" role="alert">
  本チュートリアルでは curl を用いますが、
  別のツールを利用してもかまいません。
</div>

```shell theme={null}
$ 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'
```

### トークンレスポンス

上記のトークンリクエストの結果、トークンレスポンスは以下のような内容になります。

```json theme={null}
{
  "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"
}
```

<img src="https://mintcdn.com/authlete/g-UM9YXVfm3jeKy0/protocols-and-flows/compliance-profiles/java-oauth-server_06.png?fit=max&auto=format&n=g-UM9YXVfm3jeKy0&q=85&s=285dfb5082760b9825f5dc12c034b5b0" alt="" width="892" height="303" data-path="protocols-and-flows/compliance-profiles/java-oauth-server_06.png" />

クライアント（本チュートリアルでは curl コマンド）と java-oauth-server との接続が相互 TLS ではないため、java-oauth-server はクライアント証明書を取得できませんでした。結果的に java-oauth-server から Authlete API ([/auth/token API](http://docs.authlete.com/#auth-token-api)) へのリクエストにもクライアント証明書は含まれず、クライアント証明書にひもづくアクセストークンが発行できなかったため、Authlete が [A244308 エラー](https://docs.authlete.com/#A244308) を返却しています。

<div class="alert alert-info" role="alert">
  本チュートリアルではレスポンスに
  `"error_description"`, `"error_uri"` を含んでいますが、
  これらは Authlete の設定により省略可能です。
  詳細は [サービス管理](/ja/configuration-reference/service-settings/service-management)をご参照ください。
</div>

このエラーを解消するために、次のセクションにて、java-oauth-server がクライアント証明書を受け取れるように設定していきます。

# 認可サーバーの TLS 化

本セクションでは以下の作業を行います。

* リバースプロキシーの設定
* クライアントの設定

設定後の構成は以下の図の通りです。
先のセクションでは、Web ブラウザとクライアントの接続先は java-oauth-server ([http://localhost:8080](http://localhost:8080)) でしたが、設定後は
リバースプロキシーとして前段に配置した Apache ([https://as.example.com:8443](https://as.example.com:8443)) に変更します。
また curl については、Apache への接続時にクライアント認証を試みます。

<img src="https://mintcdn.com/authlete/g-UM9YXVfm3jeKy0/protocols-and-flows/compliance-profiles/java-oauth-server_11.svg?fit=max&auto=format&n=g-UM9YXVfm3jeKy0&q=85&s=88f376a3b4388ec55c31e7749538e575" alt="" width="712" height="371" data-path="protocols-and-flows/compliance-profiles/java-oauth-server_11.svg" />

## リバースプロキシーの設定 (1)

### FQDN の設定

この後ローカル環境にインストールする Apache に対して、Web ブラウザと curl が
`as.example.com` という FQDN でアクセスできるように、本チュートリアルでは `/etc/hosts` に以下を追加します。

```text theme={null}
127.0.0.1 as.example.com
```

### Apache のインストール

チュートリアルの実行環境に Apache をインストールします。

<div class="alert alert-info" role="alert">
  本チュートリアルでは [Homebrew](https://brew.sh/index_ja) を用いて Mac にインストールしますが、
  そのほかのインストール方法や、あるいは Apache ではない別のリバースプロキシーを用いてもかまいません。
</div>

```shell theme={null}
$ brew install httpd
```

本チュートリアルでは、Apache の設定ファイルが `/usr/local/etc/httpd` 以下に配置されたものとします。

### サーバ証明書の作成・配置

<div class="alert alert-warning" role="alert">
  本チュートリアルでは簡易的な動作確認のために自己署名証明書を用います。
</div>

#### RSA 秘密鍵と公開鍵証明書の生成

OpenSSL を用いて、Apache に設定する秘密鍵と公開鍵証明書を生成します。

<div class="alert alert-info" role="alert">
  本チュートリアルでは OpenSSL を用いますが、
  別のツールを利用してもかまいません。
</div>

```shell theme={null}
$ 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'
-----
```

この結果、`server.key`（秘密鍵）と `server.crt`（公開鍵証明書）の 2 つのファイルが生成されます。

#### 秘密鍵と公開鍵証明書の配置

生成された 2 つのファイルを任意の場所に配置します。本チュートリアルでは配置場所を `/usr/local/etc/httpd` とします。

```shell theme={null}
$ sudo cp -p server.key server.crt /usr/local/etc/httpd/.
Password:
```

### Apache の TLS 設定

<div class="alert alert-info" role="alert">
  設定ファイルの記述は Apache のインストール形態によって異なる可能性があります。
  環境に応じて適宜修正してください。
</div>

#### httpd.conf

本チュートリアルでは Apache の基本的な設定として以下を行います。

* ポート 8080 をリッスンしない（java-oauth-server が 8080 を使うため）
* mod\_proxy, mod\_ssl 関連を有効化（リバースプロキシーかつ TLS 接続を受けつけるため）

設定ファイル `httpd.conf` に対する具体的な変更点は以下の通りです。
TLS 関連の設定は別のファイル (`extra/httpd-ssl.conf`) に記述した内容をインクルードします。

```diff theme={null}
$ 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
```

#### extra/httpd-ssl.conf

<div class="alert alert-warning" role="alert">
  本チュートリアルの設定は簡易的な動作確認のために最低限必要な項目のみになっています。
  実サービスにおける TLS 設定としては不十分であることにご留意ください。
</div>

本チュートリアルでは Apache の TLS 関連の設定として以下を行います。

* FQDN を as.example.com に変更（ポートは 8443 のまま）
* FAPI 準拠（TLS 1.2 に限定し、また使用可能な暗号スイートを制限）
* クライアント証明書を X-Ssl-Cert ヘッダに格納（このヘッダにクライアント証明書がセットされている場合、java-oauth-server の /api/token エンドポイントはそれを抽出し、Authlete API (/auth/token API) へのリクエストに含める）
* [https://as.example.com:8443/](https://as.example.com:8443/) へのリクエストを [http://localhost:8080/](http://localhost:8080/)  (java-oauth-server) に転送するリバースプロキシーとして設定

設定ファイル `extra/httpd-ssl.conf` に対する具体的な変更点は以下の通りです。

```diff theme={null}
$ 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/"
```

### Apache の起動

`apachectl` コマンドを用いて Apache を起動します。

```shell theme={null}
$ apachectl start
```

起動後、Web ブラウザを用いて [https://as.example.com:8443](https://as.example.com:8443) にアクセスし、
[http://localhost:8080](http://localhost:8080) と同一の、java-oauth-server のトップページが表示されることを確認します。

次のセクションでは、トークンリクエストを送信するクライアント (curl) のための、
秘密鍵と公開鍵証明書を準備します。

## クライアントの設定

### クライアント証明書の作成

<div class="alert alert-warning" role="alert">
  本チュートリアルでは簡易的な動作確認のために自己署名証明書を用います。
</div>

#### RSA 秘密鍵と公開鍵証明書の生成

以下のコマンドを実行し、秘密鍵と公開鍵証明書を生成します。

```shell theme={null}
$ 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'
-----
```

この結果、`client.key`（秘密鍵）と `client.crt`（公開鍵証明書）の 2 つのファイルが生成されます。
これらを、curl を用いたトークンリクエスト送信の際に用います。

## FAPI 認可フローの実行 (2)

### 認可リクエスト・認可レスポンス

[FAPI 認可フローの実行 (1)](#fapi-認可フローの実行-1) と同様に認可リクエストを行います。

<div class="alert alert-info" role="alert">
  認可リクエストの送信先は、
  先ほどと同じ [http://localhost:8080/api/authorization](http://localhost:8080/api/authorization) でも、
  Apache [https://as.example.com:8443/api/authorization](https://as.example.com:8443/api/authorization) でも、どちらでもかまいません。
</div>

返却される認可レスポンスから `code` パラメーターの値を抽出します。本チュートリアルでは次の値となります。

```text theme={null}
7Y5h...zp_4
```

### トークンリクエスト

トークンリクエストを組み立て、java-oauth-server のトークンエンドポイント (/api/token) に送信します。
[FAPI 認可フローの実行 (1)](#fapi-認可フローの実行-1) とは以下の点が異なります。

* `http://localhost:8080` ではなく、`https://as.example.com:8443` に接続する
* `client_secret` ではなく、秘密鍵 (`client.key`) および公開鍵証明書 (`client.crt`) を用いる

結果的に、実行する curl コマンドは以下のようになります。
（`client_id`, `code` の値は適宜変更してください）

```shell theme={null}
$ 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'
```

### トークンレスポンス

上記のトークンリクエストの結果、トークンレスポンスは以下のような内容になります。

```json theme={null}
{
  "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
}
```

クライアント証明書を指定し、相互 TLS 接続を行った結果、アクセストークン（本チュートリアルでは `nbN3...LAU8`）
を取得できました。この処理の裏では、Authlete が、アクセストークンとクライアント証明書をひもづけています。

次のセクションでは、アクセストークンを用いてリソースサーバーの API にアクセスを試みます。

# リソースサーバーの設定

本セクションでは以下の作業を行います。

* java-resource-server の導入
* 接続テスト

設定後の構成は以下の図の通りです。

<img src="https://mintcdn.com/authlete/g-UM9YXVfm3jeKy0/protocols-and-flows/compliance-profiles/java-resource-server_01.svg?fit=max&auto=format&n=g-UM9YXVfm3jeKy0&q=85&s=9c4ca498cd757483fee73f8f64d74dd8" alt="" width="712" height="371" data-path="protocols-and-flows/compliance-profiles/java-resource-server_01.svg" />

## java-resource-server の設定

[java-resource-server のドキュメント](https://github.com/authlete/java-resource-server#how-to-run)に従い、ダウンロードと設定を行います。

### ダウンロード

`git` コマンドを用いて java-resource-server をダウンロードします。

```shell theme={null}
$ git clone https://github.com/authlete/java-resource-server.git
```

### 設定

設定ファイル `authlete.properties` の以下の行を編集します。
[java-oauth-server に設定したもの](#java-oauth-server-の設定)と同じ API キーと API シークレットを指定してください。

```shell theme={null}
service.api_key = <your API key e.g. 1450...0338>
service.api_secret = <your API key e.g. VEIl...0cEs>
```

### 起動

`mvn` コマンドを用いて java-resource-server を起動します。

```shell theme={null}
$ mvn jetty:run
```

### 動作確認

Web ブラウザから [http://localhost:8081](http://localhost:8081) にアクセスし、以下のページが表示されることを確認します。

<img src="https://mintcdn.com/authlete/g-UM9YXVfm3jeKy0/protocols-and-flows/compliance-profiles/java-resource-server_02.png?fit=max&auto=format&n=g-UM9YXVfm3jeKy0&q=85&s=bd00e2f7ad0ab937c74c3148cfbbd2f7" alt="" width="1434" height="1640" data-path="protocols-and-flows/compliance-profiles/java-resource-server_02.png" />

## API リクエストの実行 (1)

`curl` コマンドを用いて、java-resource-server の「[カントリーエンドポイント](https://github.com/authlete/java-resource-server/blob/master/README.ja.md#%E3%82%AB%E3%83%B3%E3%83%88%E3%83%AA%E3%83%BC%E3%82%A8%E3%83%B3%E3%83%89%E3%83%9D%E3%82%A4%E3%83%B3%E3%83%88)」に、アクセストークン付きの API リクエストを試みます。
まず [FAPI 認可フローの実行 (2)](#fapi-認可フローの実行-2) によりアクセストークンを取得します。
本チュートリアルでは以下の値となります。

```text theme={null}
6Ivp...LiM4
```

このアクセストークンを `Authorization` ヘッダーにセットし、API リクエストを行います。
以下はリクエスト・レスポンスの例です。`curl` コマンドに `-v` オプションを付与し、
ヘッダー情報を出力しています。

```shell theme={null}
$ 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)
...
```

クライアント（本チュートリアルでは curl コマンド）と java-resource-server との接続が相互 TLS ではないため、java-resource-server はクライアント証明書を取得できませんでした。結果的に java-resource-server から Authlete API [/auth/introspection API](http://docs.authlete.com/#auth-introspection-api) へのリクエストにもクライアント証明書は含まれず、クライアント証明書とアクセストークンとのひもづけが確認できなかったため、Authlete が [A065304 エラー](https://docs.authlete.com/#A065304) を返却しています。

このエラーを解消するために、次のセクションにて、java-resource-server がクライアント証明書を受け取れるように設定していきます。

# リソースサーバーの TLS 化

本セクションでは以下の作業を行います。
基本的には、前半のセクションにて java-oauth-server に関して行った設定と同様です。

* リバースプロキシーの追加設定

設定後の構成は以下の図の通りです。
リバースプロキシーとなる Apache ([https://rs.example.com:8443](https://rs.example.com:8443)) を経由して java-resource-server に接続するようにします。
また curl は Apache への接続時にクライアント認証を試みます。

<img src="https://mintcdn.com/authlete/g-UM9YXVfm3jeKy0/protocols-and-flows/compliance-profiles/java-resource-server_11.svg?fit=max&auto=format&n=g-UM9YXVfm3jeKy0&q=85&s=267de17f0b1b02a156597c93601f4648" alt="" width="712" height="371" data-path="protocols-and-flows/compliance-profiles/java-resource-server_11.svg" />

## リバースプロキシーの設定 (2)

### FQDN の設定

Apache に対して、curl が
`rs.example.com` という FQDN でアクセスできるよう、[リバースプロキシーの設定 (1)](#リバースプロキシーの設定-1)
にて追加した `/etc/hosts` の行に、以下のように追記します。

```text theme={null}
127.0.0.1 as.example.com rs.example.com
```

### Apache の TLS 設定

#### extra/httpd-ssl.conf

Apache の TLS 関連の設定として、以下を `extra/httpd-ssl.conf` ファイルに追記します。
サーバー名やプロキシー先を除けば、先の[リバースプロキシーの設定 (1)](#リバースプロキシーの設定-1) における内容と同様です。

* rs.example.com:8443 に対する処理の内容を定義
* FAPI 準拠（TLS 1.2 に限定し、また使用可能な暗号スイートを制限）
* クライアント証明書を X-Ssl-Cert ヘッダに格納（このヘッダにクライアント証明書がセットされている場合、java-resource-server の /api/country エンドポイントはそれを抽出し、Authlete API (/auth/introspection API) へのリクエストに含める）
* [https://rs.example.com:8443/](https://rs.example.com:8443/) へのリクエストを [http://localhost:8081/](http://localhost:8081/)  (java-resouce-server) に転送するリバースプロキシーとして設定

具体的な追加内容は以下の通りです。

```apache theme={null}
<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>                                  
```

### Apache の起動

`apachectl` コマンドを用いて Apache を停止・起動します。

```shell theme={null}
$ apachectl stop && apachectl start
```

起動後、Web ブラウザを用いて [https://rs.example.com:8443](https://rs.example.com:8443) にアクセスし、
[http://localhost:8081](http://localhost:8081) と同一の、java-resource-server のトップページが表示されることを確認します。

## API リクエストの実行 (2)

[API リクエストの実行 (1)](#api-リクエストの実行-1) と同様に、
`curl` コマンドを用いて API リクエストを試みます。
まず [FAPI 認可フローの実行 (2)](#fapi-認可フローの実行-2) によりアクセストークンを取得します。
本チュートリアルでは以下の値となります。

```text theme={null}
6Ivp...LiM4
```

このアクセストークンを Authorization ヘッダーにセットし、API リクエストを行います。
先ほどとは以下の点が異なります。

* `http://localhost:8081` ではなく、`https://rs.example.com:8443` に接続する
* アクセストークンに加えて、秘密鍵 (`client.key`) および公開鍵証明書 (`client.crt`) も用いる

結果的に、実行する curl コマンドは以下のようになります。

```shell theme={null}
$ curl -v -X GET http://localhost:8081/api/country/JP \
-H 'Authorization: Bearer 6Ivp...LiM4' \
--key client.key --cert client.crt --insecure
...
```

実行後、API レスポンスとして以下の内容が返却されれば、動作確認は完了です。

```json theme={null}
{
  "name": "Japan",
  "alpha2": "JP",
  "alpha3": "JPN",
  "numeric": 392,
  "currency": "JPY"
}
```

<img src="https://mintcdn.com/authlete/g-UM9YXVfm3jeKy0/protocols-and-flows/compliance-profiles/java-resource-server_12.png?fit=max&auto=format&n=g-UM9YXVfm3jeKy0&q=85&s=54824456493fb0200c198bb8cd1ad169" alt="" width="1776" height="568" data-path="protocols-and-flows/compliance-profiles/java-resource-server_12.png" />

相互 TLS 接続を行うことにより、クライアント証明書とアクセストークンとのひもづけが確認でき、
API リクエストが期待通り処理されたことを示しています。

# まとめ

本チュートリアルでは、FAPI Basics の設定を行った Authlete サービスをバックエンドとし、
リファレンス実装 (java-oauth-server, java-resource-server) とリバースプロキシーを用いて、
FAPI 準拠の認可フローと API リクエストの動作を確認しました。
