Interested in a ServiceNow event built for developers? Registration for now[dev]26 is officially open!

JunshuO
ServiceNow Employee

はじめに

一部の統合では、認証フローで実際のアクセストークンを要求する前に JSON Web トークン (JWT) を生成する必要があります。認証エンドポイントとclient_idとclient_secretを直接交換する代わりに、発行者、件名、タイムスタンプ、その他のIDなどの特定のクレームを含む署名付き JWT がシステムで予期されます。このようなシナリオでは、clientId、clientSecret、追加のクレームなどの値を使用して、プロバイダーの要件に従って JWT を構築するカスタムスクリプトを ServiceNow に実装する必要がある場合があります。以下に、これをどのように実装できるかの概要を示します。


1. JWT の生成

ServiceNowでは、次のような入力を受け入れるスクリプトインクルードを作成します client_id client_secret subject 、およびその他のクレーム。次に、正しいクレーム(iss、sub、iatなど)でJWTを構築し、それに署名し(この場合はHS256)、トークンを返します。

 

var JWTGenerator = Class.create();
JWTGenerator.prototype = {

    initialize: function () {},

    /**
     * params = {
     *   clientId: "",        // iss
     *   subject:  "",  // sub
     *   issuedAt: <GlideDateTime>,   
     *   secret:   "<CLIENT_SECRET>",
     *   user:     ""    
     * }
     */
    generate: function (params) {
        var now = new GlideDateTime();
        var issuedAt = params.issuedAt || now;

        // ----- HEADER (order: typ, alg) -----
        var headerObj = {};
        headerObj.typ = "JWT";
        headerObj.alg = "HS256";

        var headerJson = JSON.stringify(headerObj);
        var encodedHeader = this._base64UrlSafe(this._b64EncodeString(headerJson));

        // ----- PAYLOAD (order: sub, iss, iat, user) -----
        var payloadObj = {};
        payloadObj.sub = params.subject;
        payloadObj.iss = params.clientId;
        payloadObj.iat = this._toEpochSeconds(issuedAt);

        if (params.user)
            payloadObj.user = params.user;

        var payloadJson = JSON.stringify(payloadObj);
        var encodedPayload = this._base64UrlSafe(this._b64EncodeString(payloadJson));

        var unsignedToken = encodedHeader + "." + encodedPayload;

        // ----- SIGNATURE (HS256) -----
        var mac = new global.CertificateEncryption();

        // Key must be base64 so HMAC uses the same raw bytes as the Java/Auth0 code
        var keyBase64 = this._b64EncodeString(params.secret);

        var signatureBase64 = mac.generateMac(
            keyBase64,
            "HmacSHA256",
            unsignedToken
        );

        var encodedSignature = this._base64UrlSafe(signatureBase64);

        return unsignedToken + "." + encodedSignature;
    },

    // ---------- helpers ----------

    _b64EncodeString: function (str) {
        try {
            if (typeof GlideStringUtil !== 'undefined' &&
                GlideStringUtil.base64Encode) {
                return GlideStringUtil.base64Encode(str);
            }
        } catch (e) {
            // ignore and fall back to gs
        }
        return gs.base64Encode(str);
    },

    _toEpochSeconds: function (gdt) {
        return Math.floor(gdt.getNumericValue() / 1000);
    },

    _base64UrlSafe: function (b64) {
        b64 = b64.split("=").join("");   // remove padding
        b64 = b64.split("+").join("-");  // + -> -
        b64 = b64.split("/").join("_");  // / -> _
        return b64;
    },

    type: "JWTGenerator"
};

 

重要な注意事項:

  • CertificateEncryption() API は、ソリューションがカスタムスコープ内で機能するようにするために使用されます。

  • クレームは、認証 API が期待するものと正確に一致する必要があります。

これで、上記のスクリプトインクルードを、アクション入力として userId を想定して、Workflow Studio/フローデザイナーのアクションスクリプトから呼び出すことができます。

 

(function execute(inputs, outputs) {

    var now = new GlideDateTime();

    var params = {

        clientId: gs.getProperty({sysPropertyNameClientId}),        // sys_property of "Password2" type
        subject: {custom_value} + inputs.user + '@' + inputs.user,
        issuedAt: now,
        secret: gs.getProperty({sysPropertyNameClientSecret}),  // sys_property of "Password2" type
        user: inputs.user
    };

    var jwt = new x_{custom_app_name}.JWTGenerator.generate(params);

    // Return the JWT to the Action outputs
    outputs.jwt_token = jwt;

})(inputs, outputs);

2. JWT の送信とアクセストークンの取得

JWT を取得したら、次のステップでは、認証エンドポイントを呼び出し、必要なヘッダーまたは本文パラメーターでトークンを送信します。その後、API はアクセストークンを返します。これを後続の呼び出しに使用します。

 

プレースホルダー – REST 呼び出し + ヘッダー:

POST https://example.com/oauth2/token
Headers:
  Content-Type: application/x-www-form-urlencoded
  Authorization: Bearer <your_jwt_token>

トークン API から応答を受信したら、応答本文の JSON を解析して、必要なアクセストークンを取得する必要があります。

 

最後に、フローデザイナーアクションには次の手順が含まれます。

  1. JWT スクリプトインクルードを呼び出し、JWT を生成します。

  2. REST メッセージを呼び出してアクセストークンを取得します。

  3. REST メッセージの応答を解析し、アクセストークンを取得します。

 

JWT を外部で検証する

開発中は、jwt.io のようなツールを使用して、生成された JWT を検証することが必要になる場合があります。これにより、適切なアルゴリズム (HS256/RS256) などが使用され、クレームが正しく、有効な署名が存在することが保証されます。

 

まとめ
JWT を生成し、それをアクセストークンと交換してから、そのトークンを統合で使用するこのパターンは確実に機能し、ServiceNow 内で再利用可能なフローデザイナーアクションとしてパッケージ化できます。これは、JWT ベアラー認証を想定している API を扱う場合に役立つアプローチです。


この記事は機械翻訳されております。最新は元となる記事をご覧ください: https://www.servicenow.com/community/workflow-data-fabric-articles/generating-jwt-token-for-oauth2-i...

免責事項: 一部の日本語は、翻訳ソフトウェアを使用してお客様の便宜のために翻訳されています。正確な翻訳をご提供できるよう相当な努力を払っておりますが、いかなる自動翻訳も人間の翻訳者に代わすることはなく、そのようなことは意図されておりません。翻訳は「現状のまま」提供されています。他言語への翻訳の的確性、信頼性または正確性については、明示または黙示を問わず、いかなる保証も行われません。翻訳ソフトには限界があるため、一部のコンテンツが正確に翻訳されていない場合があります。これらの資料の公用言語は英語です。翻訳の際に生じる相違または不一致は、コンプライアンスまたは履行の目的に関しては拘束力を有さず、法的効力はないものとします。