Функция Javascript для создания Firebase CustomToken - PullRequest
0 голосов
/ 13 октября 2019

Я создаю собственный скрипт TamperMonkey для Firebase, чтобы провести локальное тестирование на моем веб-сайте. Вставляя UID данного пользователя аутентификации FireBase, я создаю для него customToken .

Вот мой текущий код

// ==UserScript==
// @name         my-name
// @namespace    my-namespace
// @version      1.0
// @author       Myself
// @match        XXXX-my-website-XXXX
// @require      https://www.gstatic.com/firebasejs/6.6.2/firebase-app.js
// @require      https://www.gstatic.com/firebasejs/6.6.2/firebase-auth.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/hmac-sha256.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/components/enc-base64-min.js
// @grant        none
// ==/UserScript==

(function() {
    function generateCustomToken(uid) {
        if(typeof CryptoJS === undefined) {
            alert("CryptoJS not found");
            return;
        }

        // https://console.firebase.google.com/project/my-project-id/settings/serviceaccounts/adminsdk
        var serviceAccount = { ... content of json service account file ... };

        // https://firebase.google.com/docs/auth/admin/create-custom-tokens#create_custom_tokens_using_a_third-party_jwt_library
        var header = {
            "alg": "RS256",
            "typ": "JWT"
        };

        var seconds = Math.trunc(new Date().getTime() / 1000);
        var payload = {
            iss : serviceAccount.client_email,
            sub : serviceAccount.client_email,
            aud : "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
            iat : seconds,
            exp : seconds + (60*60), // Maximum expiration time is one hour
            uid : uid,
            claims : {
                premium_account : false
            }
        };

        // https://github.com/firebase/php-jwt/blob/master/src/JWT.php#L156
        var segments = [];

        segments.push(base64url(CryptoJS.enc.Utf8.parse(JSON.stringify(header))));
        segments.push(base64url(CryptoJS.enc.Utf8.parse(JSON.stringify(payload))));

        var signingInput = segments.join(".");
        var secret = serviceAccount.private_key
                    .replace('-----END PRIVATE KEY-----', '') // remove head
                    .replace('-----BEGIN PRIVATE KEY-----', '') // remove tail
                    .replace(/\n/g, ''); // remove all new-line chars

        segments.push(base64url(CryptoJS.HmacSHA256(signingInput, secret)));
        return segments.join(".");
    }

    /**
    * https://codepen.io/jpetitcolas/pen/zxGxKN
    */
    function base64url(source) {
        // Encode in classical base64
        var encodedSource = CryptoJS.enc.Base64.stringify(source);

        // Remove padding equal characters
        encodedSource = encodedSource.replace(/=+$/, '');

        // Replace characters according to base64url specifications
        encodedSource = encodedSource.replace(/\+/g, '-');
        encodedSource = encodedSource.replace(/\//g, '_');

        return encodedSource;
    }

    function firebaseLogin(customToken) {
        // FIXME omitted code, firebase initialize

        firebase
            .auth()
            .signInWithCustomToken(customToken)
            .then(function(response) {
                alert("Success signInWithCustomToken");
            })
            .catch(function(error) {
                alert("signInWithCustomToken ERROR\n" + error.code + "\n" + error.message);
            });
    }
})();

Я следовал различным примерам, которые нашел (я связал их в коде) и официальная документация для использования пользовательских клиентов.

Я прочитал код много раз, и все, кажется, в порядке, но из-за данной ошибки мне кажется, что я упускаю что-то очень простое, что я не могу увидеть при генерации токена jwt.

POST https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyCustomToken?key=xxx-my-api-key-xxx
{"token":"xxx-generated-custom-token-xxx","returnSecureToken":true}

HTTP RESPONSE 400 
{
  "error": {
    "code": 400,
    "message": "INVALID_CUSTOM_TOKEN",
    "errors": [
      {
        "message": "INVALID_CUSTOM_TOKEN",
        "domain": "global",
        "reason": "invalid"
      }
    ]
  }
}

КакTamperMonkey, который предназначен для непосредственного запуска внутри браузера, среда Node или другие недоступны, поэтому я использую «сырые» библиотеки вместо более интегрированных.

Вы видите какую-либо ошибку при генерациижетон JWT?

1 Ответ

1 голос
/ 13 октября 2019

Решено с использованием jsrsasign (Это одна из библиотек JS, предложенная на сайте https://jwt.io/). Я до сих пор не знаю, в чем проблема, думаю, что-то связано с анализом секретного ключа. Большая часть кода теперь управляется библиотекой, поэтому поток работает правильно.

Вот обновленный код, связанный с генерацией токенов:

Добавить в заголовок скрипта:

 // @require      https://cdnjs.cloudflare.com/ajax/libs/jsrsasign/8.0.12/jsrsasign-all-min.js

И функция для создания JWT

    var serviceAccount = { ... content of json service account file ... };

    // https://firebase.google.com/docs/auth/admin/create-custom-tokens#create_custom_tokens_using_a_third-party_jwt_library
    var header = {
        "alg": "RS256",
        "typ": "JWT"
    };

    var payload = {
        iss : serviceAccount.client_email,
        sub : serviceAccount.client_email,
        aud : "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
        iat : KJUR.jws.IntDate.get('now'),
        exp : KJUR.jws.IntDate.get('now + 1hour'),
        uid : uid
    };

    // https://github.com/kjur/jsrsasign/wiki/Tutorial-for-JWT-generation
    var sHeader = JSON.stringify(header);
    var sPayload = JSON.stringify(payload);

    var prvKey = KEYUTIL.getKey(serviceAccount.private_key);
    var sJWT = KJUR.jws.JWS.sign("RS256", sHeader, sPayload, prvKey);

    return sJWT;
...