では、日本郵便のデジアドAPIをたたいて「住所」をゲットしてみよう。本当にOAuthかな?

体調を崩して時間が空いてしまってごめんなさい。前回の記事では、日本郵便のデジタルアドレス(デジアド)を取得して、日本郵便の提供する送り状作成アプリで使うところまでやりました。今回は、これをAPI経由で取得してみます。なんたって、「郵便番号・デジタルアドレスAPI」のページには、OAuth 2.0とOpenID Connectに対応しているというのだからやらざるを得ません。

ゆうID Biz を取得しよう

さて、ゆうIDのAPIを叩くには、郵便番号・デジタルアドレス for Biz に登録しなければなりません。登録ページに行くと、こんな画面が出ます。

ユーザー名はあとから変えられるようです。適当な名前を入力すると「登録する」ボタンが黒くなって押せるようになるので押します。

すると組織登録の画面になります。法人と個人事業主と両方行けるようです。わたしはどちらでもよかったのですが、より入力項目の多い法人の方ですすむことにしました。たまたまNATコンサルティング合同会社という会社も持っていますしね。

そして登録が終わるとユーザーリストなどの画面になります。

この画面ではユーザーリストだけでなく、組織としてどのような設定をしたかの「設定」メニュー、そして、「サービス」の下に「郵便番号・デジタルアドレスAPI」についてのページと、「デジタルアドレスから住所を検索」するためのページへのリンクが左側メニューに出てきます。さっそく、お目当ての「郵便番号・デジタルアドレスAPI」のページに行きます。

クリックするとメニューが開きます。

「システムリスト」では登録済みクライアントの一覧表示とクライアントの登録ができます。

「テスト用AI認証情報」では、テスト用APIを使うためのclient_id と client_secret の表示ができます。テスト用APIリファレンスのドキュメンテーションもあります。まずやらなければならない、テスト用APIを叩くクライアントは、ここをみながらやることになります。APIリファレンスはこんな感じです。

「Download」ボタンでOpenAPIのSpecが落ちてきそうですが、ダウンロードできませんでした。この辺は直してほしいところです。

APIリファレンスは本番用のAPIリファレンスが入っています。

利用ガイドラインには「デジタルアドレス」データの取り扱いについてなどの注意事項が書いてあります。

リリースノートは現在空白です。

データソースには、このAPIが提供しているデータのもととなるCSVが載っていたりします。

早速テスト用APIを叩いてみよう

それでは早速テスト用APIを叩いてみて、どんなふうにOAuthやOpenID Connect が使われているのかを見ていきましょう。

Access Token の取得

ドキュメンテーションによると、どうもサポートしているのはOAuth 2.0 [RFC6749] client_credentials grant のみのようです。で access token を取るのですが、このとき本来は Authorization Header で送る(サーバーはサポート必須)ないしは request body にパラメータとして入れて送るのですが、JSON でbody に入れて送るようになっています。

こんな感じです。

{
"grant_type": "client_credentials",
"client_id": "Test_Client_Identifier_String",
"secret_key": "Test_Secret_Key"
}

これは OAuth 2.0 では定義されていないので独自仕様と言っても良いでしょう。ちなみに、RFC6749で指定されている方式で送ると、Bad Request になってしまいます。

独自仕様はこれだけではありません。このときのリクエストには x-forwarded-for を必須で入れなければならないことになっています。これも独自拡張ですね。気持ちは分からなくもないですが…。ちなみに何を入れろという指定はありません。多分このclient に接続してきている端末のIP Addressを入れるのだと思います。が、RFC7239によると、x-forwarded-for はやめて、Forwarded を使うようにとされていますね。

ちなみに、APIのエンドポイントは、ドキュメンテーションのパスをクリックすると表示されるようになっています。

これらを踏まえたうえで、APIドキュメンテーションから取れるテスト用APIにリクエストを送ります。

curl -X POST https://stub-qz73x.da.pf.japanpost.jp/api/v1/j/token \
  -H "Content-Type: application/json" \
  -H "X-Forwarded-For: 64.227.48.220" \
  -d '{
    "grant_type": "client_credentials",
    "client_id": "Test_Client_Identifier_String",
    "secret_key": "Test_Secret_Key"
  }'

そうしますと、以下の感じでレスポンスが帰ってきます。

{"token":"eyJhbGciOiJSU.中略.TmrM38fAf8cgNm1QAnf-j0YFQA",
"token_type":"jwt",
"expires_in":600,
"scope":"J1"}

お、アクセストークンはJWT形式ですね。中身はこんな感じになっています。

Headerが

{
  "alg": "RS256",
  "typ": "JWT"
}

Payload

{
  "iss": "JPD",
  "sub": "DGA TOKEN",
  "scope": "J1",
  "clientId": "Biz_DaPfJapanpost_MockAPI_j3QKS",
  "ec_id": "8aeaf147-112f-4127-8cbb-2eff08a8e161",
  "iat": 1742886316,
  "exp": 1742886916
}

のようになっています。おや、typがおかしいですね。RFC9068によれば、typはat+jwtであるべきですね。

また、iss が単なるstringなのでJWKを発見することはできないので検証はできませんが、これは検証するのは日本郵便自体なので問題ないですね。sub は client_id が入るかと思ったらそうでも無いようで固定のstringのようですね。

では、デジアドを住所に解決してみよう

このアクセストークンを使って今度はsearch用のendpointにOAuthのrequestをかけます。Access Token は Authorization Header 送ることができます。X-Forwarded-For は相変わらず送る感じです。テスト用APIではテスト用のデジタルアドレス3種(A7E2FK2,JN4LKS2,QN6GQX1)と東京都千代田区に対して郵便番号、事業所個別郵便番号の検索が可能。

curl だとこんな感じですね。

curl -X GET https://stub-qz73x.da.pf.japanpost.jp/api/v1/searchcode/A7E2FK2 \
  -H "Authorization: Bearer eyJhbGci..中略..QAnf-j0YFQA" \
  -H "X-Forwarded-For: 64.227.48.220" \
  -H "Accept: application/json"

すると、以下のような感じで帰ってきます。

{
	"page": 1,
	"limit": 1000,
	"count": 1,
	"searchtype": "dgacode",
	"addresses": [
		{
			"dgacode": "A7E2FK2",
			"zip_code": "100-0005",
			"pref_code": "13",
			"pref_name": "東京都",
			"pref_kana": null,
			"pref_roma": null,
			"city_code": "13101",
			"city_name": "千代田区",
			"city_kana": null,
			"city_roma": null,
			"town_name": "丸の内",
			"town_kana": null,
			"town_roma": null,
			"biz_name": null,
			"biz_kana": null,
			"biz_roma": null,
			"block_name": "2丁目7−2",
			"other_name": "部屋番号:サンプル1",
			"address": "東京都千代田区丸の内2丁目7−2部屋番号:サンプル1",
			"longitude": null,
			"latitude": null
		}
	]
}

まぁ、レスポンスは OpenID Connect のUserInfo response というわけでもなく、独自ですね。

ちなみに、上記3つ以外のデジアドを指定すると、

{
"request_id":"848f5369-56fb-4488-aecd-b82599a1b2f9",
"error_code":"404-1029-0001",
"message":"該当するデジアドがありませんでした"
}

と帰ってきます。

本番環境にアクセスしてみよう

さて、うまくいったので、今度は本番環境にアクセスしてみましょう。

やることはテスト用と同じで、単にアクセス先とclient_id, client_secret が変わるだけです。本番用のclient_id, client_secret は「システムリスト」メニューでクライアント登録することによってゲットできます。

トークンをゲットするには、アクセス先を https://api.da.pf.japanpost.jp/api/v1/j/token に変えてリクエストします。

curl -X POST https://api.da.pf.japanpost.jp/api/v1/j/token \
  -H "Content-Type: application/json" \
  -H "X-Forwarded-For: 64.227.48.220" \
  -d '{
    "grant_type": "client_credentials",
    "client_id": "クライアントID",
    "secret_key": "クライアントシークレット"
  }'

Access Token が返ってくるので、これを使ってリクエストします。すると、先程のようなJSONが帰ってきます。なお、デジアドの代わりに郵便番号を指定することもできます。

  curl -X GET https://api.da.pf.japanpost.jp/api/v1/searchcode/6180000 \
  -H "Authorization: Bearer eyJhbGciOiJS..中略..wV0si0TiQ" \
  -H "X-Forwarded-For: 64.227.48.220" \
  -H "Accept: application/json"

するとこんなふうに帰ってきます。
{
  "page": 1,
  "limit": 1000,
  "count": 2,
  "searchtype": "zipcode",
  "addresses": [
    {
      "dgacode": null,
      "zip_code": "6180000",
      "pref_code": "26",
      "pref_name": "京都府",
      "pref_kana": "キョウトフ",
      "pref_roma": "KYOTO",
      "city_code": "26303",
      "city_name": "乙訓郡大山崎町",
      "city_kana": "オトクニグンオオヤマザキチョウ",
      "city_roma": "OTOKUNI-GUN OYAMAZAKI-CHO",
      "town_name": "",
      "town_kana": "",
      "town_roma": "",
      "biz_name": null,
      "biz_kana": null,
      "biz_roma": null,
      "block_name": null,
      "other_name": null,
      "address": null,
      "longitude": null,
      "latitude": null
    },
    {
      "dgacode": null,
      "zip_code": "6180000",
      "pref_code": "27",
      "pref_name": "大阪府",
      "pref_kana": "オオサカフ",
      "pref_roma": "OSAKA",
      "city_code": "27301",
      "city_name": "三島郡島本町",
      "city_kana": "ミシマグンシマモトチョウ",
      "city_roma": "MISHIMA-GUN SHIMAMOTO-CHO",
      "town_name": "",
      "town_kana": "",
      "town_roma": "",
      "biz_name": null,
      "biz_kana": null,
      "biz_roma": null,
      "block_name": null,
      "other_name": null,
      "address": null,
      "longitude": null,
      "latitude": null
    }
  ]
}

まとめ

というわけで、まとめ。

  1. デジアド変換APIはRFC6749のclient credentials grant ぽい独自仕様でAccess Token を取得する。このAccess Token は JWT になっているが、typは RFC9068で指定されるようにat+jwtになっておらずJWTになっている。
  2. 取得したAccess Token を今度はRFC6750にそう形で送信して、当該デジアドに登録してある文字列(住所とは限らない)を取得する。
    • 文字列は任意のものを登録できるので、たとえば、address として「東京都から届いた手紙には「あなたは存在しません」。鏡にも映らず、人も気づかない。 私は、静かに消えていった。」なんてことを登録することもできる1
  3. OpenID Connect っぽいところは今のところ見つから無い。
  4. デジアドの代わりに郵便番号を指定して住所を取得することもできる。重複している場合にはarrayで複数返ってくる。

ところで、郵便番号ってガンガン重複してるんですね。情報によると、1,341 件も重複しているとか。ものによると県まで違うものも…。どうしてこうなった…。

脚注

  1. まぁ、OpenID Connect の address claim もそうだけど

コメントを残す

This site uses Akismet to reduce spam. Learn how your comment data is processed.