soap-apiauthenticationsecuritytutorial

SOAP API 認証ガイド: Basic Auth、WS-Security UsernameToken、カスタムヘッダー

SOAPless Team8 min read

SOAP API の認証は、REST API よりひと手間どころでは済まないことがよくあります。REST なら Authorization ヘッダーや API キーで終わる場面でも、SOAP では HTTP レイヤーで認証したり、SOAP Header に UsernameToken を入れたり、独自ヘッダーを再現したりします。

実務でよく出てくるのは、だいたい次の 3 つです。

  • HTTP Basic Auth
  • WS-Security UsernameToken
  • 独自の SOAP ヘッダー

この記事では、この 3 つを中心に整理します。

認証方式の全体像

SOAP API で現実によく出てくる認証方式は、まず次の 4 つです。

認証方式複雑度使用頻度セキュリティ
HTTP Basic Auth低(HTTPS 必須)
WS-Security UsernameToken
WS-Security with Digest
独自 SOAP ヘッダー中〜高実装次第

方式 1: HTTP Basic Auth

最もシンプルな方法です。SOAP の仕様ではなく、HTTP レイヤーで認証します。

# curl での Basic Auth 付き SOAP 呼び出し
curl -X POST https://example.com/service \
  -u "username:password" \
  -H "Content-Type: text/xml; charset=utf-8" \
  -H 'SOAPAction: "http://example.com/services/GetUser"' \
  -d '<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
               xmlns:tns="http://example.com/services">
  <soap:Body>
    <tns:GetUserRequest>
      <tns:userId>42</tns:userId>
    </tns:GetUserRequest>
  </soap:Body>
</soap:Envelope>'
// Node.js: node-soap で Basic Auth
const soap = require('soap');

const client = await soap.createClientAsync(wsdlUrl);
client.setSecurity(new soap.BasicAuthSecurity('username', 'password'));

const [result] = await client.GetUserAsync({ userId: 42 });
# Python: zeep で Basic Auth
from zeep import Client
from requests import Session
from requests.auth import HTTPBasicAuth

session = Session()
session.auth = HTTPBasicAuth('username', 'password')

from zeep.transports import Transport
transport = Transport(session=session)
client = Client(wsdl_url, transport=transport)

見分ける手掛かりは次のようなものです。

  • 401 Unauthorized が返る
  • WWW-Authenticate: Basic が見える
  • 接続手順書に「Basic 認証」と書かれている

注意: Basic Auth はユーザー名とパスワードを Base64 エンコードしただけなので、必ず HTTPS で通信してください。

方式 2: WS-Security UsernameToken

SOAP らしい認証方式として一番よく出てくるのがこれです。SOAP エンベロープの Header にセキュリティトークンを入れます。

プレーンテキスト UsernameToken

最もシンプルな WS-Security の形式です。

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <wsse:Security
      xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
      xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
      <wsse:UsernameToken wsu:Id="UsernameToken-1">
        <wsse:Username>apiuser</wsse:Username>
        <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">secretpassword</wsse:Password>
        <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">dGVzdG5vbmNl</wsse:Nonce>
        <wsu:Created>2026-03-15T10:00:00.000Z</wsu:Created>
      </wsse:UsernameToken>
    </wsse:Security>
  </soap:Header>
  <soap:Body>
    <!-- オペレーションの内容 -->
  </soap:Body>
</soap:Envelope>

各要素の意味は次の通りです。

  • Username: API ユーザー名
  • Password: パスワード(Type 属性で PasswordText または PasswordDigest を指定)
  • Nonce: リプレイ攻撃防止用のランダム値(Base64 エンコード)
  • Created: タイムスタンプ(サーバーがタイムスキューを検証する)

PasswordDigest 方式

PasswordText ではなく PasswordDigest を要求するサービスもあります。こちらは nonce と timestamp を含めてハッシュ化します。

PasswordDigest = Base64(SHA-1(Nonce + Created + Password))
// Node.js での PasswordDigest 計算
const crypto = require('crypto');

function createPasswordDigest(nonce, created, password) {
  const nonceBuffer = Buffer.from(nonce, 'base64');
  const createdBuffer = Buffer.from(created, 'utf-8');
  const passwordBuffer = Buffer.from(password, 'utf-8');

  const combined = Buffer.concat([nonceBuffer, createdBuffer, passwordBuffer]);
  const hash = crypto.createHash('sha1').update(combined).digest('base64');
  return hash;
}

const nonce = crypto.randomBytes(16).toString('base64');
const created = new Date().toISOString();
const digest = createPasswordDigest(nonce, created, 'secretpassword');
// node-soap で WS-Security を設定
const soap = require('soap');

const client = await soap.createClientAsync(wsdlUrl);
client.setSecurity(new soap.WSSecurity('apiuser', 'secretpassword', {
  hasNonce: true,
  hasTimeStamp: true,
  passwordType: 'PasswordDigest'  // または 'PasswordText'
}));

ここで詰まりやすいのは、資格情報そのものより次のような細部です。

  • PasswordTextPasswordDigest を取り違えている
  • サーバーと時刻がずれている
  • namespace や Header の形が微妙に違う
  • 本当は SOAP 1.1 / 1.2 の取り違えで、認証エラーっぽく見えている

方式 3: カスタム SOAP ヘッダー認証

一部の SOAP サービスは標準の WS-Security ではなく、独自のヘッダーで認証します。

<soap:Header>
  <auth:AuthHeader xmlns:auth="http://example.com/auth">
    <auth:ApiKey>your-api-key-here</auth:ApiKey>
    <auth:Timestamp>2026-03-15T10:00:00Z</auth:Timestamp>
    <auth:Signature>HMAC-SHA256-signature</auth:Signature>
  </auth:AuthHeader>
</soap:Header>
// node-soap でカスタムヘッダーを追加
const client = await soap.createClientAsync(wsdlUrl);

client.addSoapHeader({
  'auth:AuthHeader': {
    'auth:ApiKey': 'your-api-key-here',
    'auth:Timestamp': new Date().toISOString(),
    'auth:Signature': computeHmacSignature(apiKey, timestamp, secret)
  },
  attributes: {
    'xmlns:auth': 'http://example.com/auth'
  }
});

このカテゴリは標準化されていないので、結局はベンダーの資料とサンプルに忠実に合わせるしかありません。

WSDL から認証要件を読み取る

WSDL には WS-Policy セクションで認証要件が記述されていることがあります。

<wsp:Policy wsu:Id="SecurityPolicy">
  <sp:SupportingTokens>
    <wsp:Policy>
      <sp:UsernameToken
        sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/AlwaysToRecipient">
        <wsp:Policy>
          <sp:HashPassword/>  <!-- PasswordDigest を要求 -->
        </wsp:Policy>
      </sp:UsernameToken>
    </wsp:Policy>
  </sp:SupportingTokens>
</wsp:Policy>

確認ポイント:

  • <sp:UsernameToken> があれば WS-Security UsernameToken が必要
  • <sp:HashPassword/> があれば PasswordDigest が必須
  • <sp:TransportBinding> があれば HTTPS 前提
  • WSDL に情報が薄い場合は、別紙の接続手順書やベンダー資料を探す

認証のデバッグ

認証エラーが発生した場合は、以下の順序で確認すると切り分けやすくなります。

  1. 認証方式そのもの: Basic Auth なのか WS-Security なのかを取り違えていないか
  2. 認証情報の正確性: ユーザー名やパスワードの前後に空白や改行が入っていないか
  3. タイムスタンプのスキュー: Created のタイムスタンプがサーバー時刻と大きくずれていないか
  4. Header の形: Nonce や namespace URI、要素の並びが期待通りか
  5. 周辺条件: そもそも SOAP version や endpoint がずれていないか

認証の複雑さから解放される方法

SOAP の認証がつらいのは、1 回つながれば終わりではないからです。認証方式の理解、XML ヘッダーの再現、タイムスタンプや Nonce の扱い、障害時の切り分けが、呼び出し元ごとに何度も発生します。

SOAPless が相性よく使えるのは、こうした認証の面倒を 1 か所に集約したい時です。現在の機能としては、特に次のような接続先の SOAP と噛み合います。

  • HTTP Basic Auth
  • WS-Security UsernameToken
  • カスタム送信ヘッダー

接続先の SOAP 認証を 1 回設定しておけば、利用側のチームは API キー付きの REST JSON エンドポイントを前提に開発できます。SOAP Header を各アプリやスクリプトが毎回組み立てなくて済む、というのが一番大きい価値です。