Авторизовать GMail API с помощью JWT - PullRequest
0 голосов
/ 10 марта 2020

Я пытаюсь отправить электронное письмо через API gmail из приложения Node.js. Я работал, следуя документации и используя пакет node-mailer. Однако я заметил, что когда мы меняем пароль нашей организации, соединение перестает работать (что имеет смысл). Поэтому я пытаюсь авторизоваться с помощью JWT.

JWT сгенерирован правильно и отправлен на https://oauth2.googleapis.com/token. Затем этот запрос возвращает access_token.

Когда пришло время написать и отправить электронное письмо, я попытался просто адаптировать код, который ранее работал (в то время с client_secret, client_id и redirect_uris):

const gmail = google.gmail({ version: 'v1', auth: access_token });
  gmail.users.messages.send(
    {
      userId: 'email',
      resource: {
        raw: encodedMessage
      }
    },
    (err, result) => {
      if (err) {
        return console.log('NODEMAILER - The API returned: ' + err);
      }

      console.log(
        'NODEMAILER  Sending email reply from server: ' + result.data
      );
    }
  );

API продолжает возвращаться Error: Login Required.

Кто-нибудь знает, как решить эту проблему?

РЕДАКТИРОВАТЬ

I ' Мы изменили мой код и аутентификацию, добавив client_id и client_secret:

const oAuth2Client = new google.auth.OAuth2(
      credentials.gmail.client_id,
      credentials.gmail.client_secret,
      credentials.gmail.redirect_uris[0]
    );

    oAuth2Client.credentials = {
      access_token: access_token
    };
    const gmail = google.gmail({ version: 'v1', auth: oAuth2Client });
    gmail.users.messages.send(
      {
        userId: 'email',
        resource: {
          raw: encodedMessage
        }
      },
      (err, result) => {
        if (err) {
          return console.log('NODEMAILER - The API returned: ' + err);
        }

        console.log(
          'NODEMAILER  Sending email reply from server: ' + result.data
        );
      }
    );

Но теперь ошибка стала еще менее точной: Error: Bad Request

1 Ответ

0 голосов
/ 30 марта 2020

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

var credentials = require('../../credentials');
    const privKey = credentials.gmail.priv_key.private_key;

    var jwtParams = {
      iss: credentials.gmail.priv_key.client_email,
      scope: 'https://www.googleapis.com/auth/gmail.send',
      aud: 'https://oauth2.googleapis.com/token',
      exp: Math.floor(new Date().getTime() / 1000 + 120),
      iat: Math.floor(new Date().getTime() / 1000),
      sub: [INSERT EMAIL THAT WILL BE SENDING (not the service email, the one that has granted delegated access to the service account)]
    };

    var gmail_token = jwt.sign(jwtParams, privKey, {
      algorithm: 'RS256'
    });

    var params = {
      grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
      assertion: gmail_token
    };

    var params_string = querystring.stringify(params);

    axios({
      method: 'post',
      url: 'https://oauth2.googleapis.com/token',
      data: params_string,
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    }).then(response => {
      let mail = new mailComposer({
        to: [ARRAY OF RECIPIENTS],
        text: [MESSAGE CONTENT],
        subject: subject,
        textEncoding: 'base64'
      });

      mail.compile().build((err, msg) => {
        if (err) {
          return console.log('Error compiling mail: ' + err);
        }

        const encodedMessage = Buffer.from(msg)
          .toString('base64')
          .replace(/\+/g, '-')
          .replace(/\//g, '_')
          .replace(/=+$/, '');

        sendMail(encodedMessage, response.data.access_token, credentials);
      });
    });

Таким образом, в приведенном выше сегменте кода используется закрытый ключ для создания JSON Web Token (JWT), где: iss - учетная запись службы область действия - это конечная точка доступа к API gmail (это должно быть предварительно авторизовано), aud - это конечная точка oAuth2 API Google, exp - время истечения срока действия, iat - это время создания, а sub - электронная почта, которую использует учетная запись службы. for.

Затем токен подписывается и отправляется запрос POST к конечной точке Google oAuth2. В случае успеха я использую компонент mail Composer NodeMailer для создания электронной почты с массивом получателей, сообщением, темой и кодировкой. Затем это сообщение кодируется.

А вот моя sendMail() функция:

const oAuth2Client = new google.auth.OAuth2(
      credentials.gmail.client_id,
      credentials.gmail.client_secret,
      credentials.gmail.redirect_uris[0]
    );

    oAuth2Client.credentials = {
      access_token: access_token
    };

    const gmail = google.gmail({ version: 'v1', auth: oAuth2Client });
    gmail.users.messages.send(
      {
        userId: 'me',
        resource: {
          raw: encodedMessage
        }
      },
      (err, result) => {
        if (err) {
          return console.log('NODEMAILER - The API returned: ' + err);
        }

        console.log(
          'NODEMAILER  Sending email reply from server: ' + result.data
        );
      }
    );

В этой функции я создаю новый объект OAuth2 googleapis, используя учетные данные учетной записи службы (здесь хранится во внешнем файле для дополнительной безопасности). Затем я передаю access_token (сгенерированный в сценарии аутентификации с помощью JWT). Затем сообщение отправляется.

Обратите внимание на userId: 'me' в функции sendMail(), для меня это было критически важно.

...