Аутентификация с помощью API Google может позволить вашему веб-приложению получать доступ к сервисам от имени ваших пользователей. В этой статье я покажу, как настроить приложение для аутентификации с помощью API Google с использованием OAuth 2.0; Многие показанные примеры будут относиться к настройке интеграции между Infisical и Google, но вы сможете адаптировать их к своему собственному сценарию использования.

На высоком уровне нам нужно будет настроить приложение OAuth в Google Cloud Platform (GCP) и настроить поток OAuth 2.0 в нашем приложении для работы с ним.

Не знаете, что такое OAuth? Ознакомьтесь с букварем здесь.

Общий обзор

Прежде чем мы углубимся в то, как мы можем реализовать OAuth 2.0 с Google для доступа к API Google, полезно понять высокоуровневый поток, с которым мы будем иметь дело.

  • (A) Перенаправить пользователя из браузера в Google: пользователь нажимает кнопку в браузере и перенаправляется в Google, где он может предоставить приложению доступ к своей учетной записи Google.
  • (B) Вернуть пользователя из Google обратно в браузер: после предоставления разрешения пользователь перенаправляется обратно в браузер с помощью code .
  • (C) Выполните обмен кодом-токеном: отправьте code из браузера на сервер для обмена с Google. После обмена мы должны получить от сервиса ответ access_token, а зачастую и refresh_token .
  • (D) Используйте токен доступа для отправки запросов к API Google:С помощью access_token теперь мы можем отправлять запросы к API Google от имени пользователя. Если срок действия access_token истекает, мы можем использовать refresh_token для получения нового access_token .

Полезные советы. Теперь мы готовы реализовать OAuth 2.0 с GCP для доступа к API Google.

Настройка приложения OAuth в GCP

  1. Создайте учетную запись в GCP здесь: https://cloud.google.com.
  2. Начните с перехода к API и службам вашего проекта › Учетные данные в GCP, чтобы создать новое приложение OAuth.

3. Создайте приложение OAuth.

В форме добавьте в Разрешенные URI перенаправления URL-адрес перенаправления, например https://your-domain.com/integrations/gcp-secret-manager/oauth2/callback ; вы, конечно, можете выбрать свой собственный URL-адрес перенаправления на основе желаемой структуры маршрутизации. Это URL-адрес, на который Google перенаправит пользователя обратно после того, как он разрешит приложению доступ к своей учетной записи Google.

4. Получите Идентификатор клиента и Секрет клиента для вашего приложения Google OAuth2; держите их под рукой.

Настройка вашего веб-приложения для работы с приложением GCP OAuth.

5. Перенаправьте пользователя в GCP из интерфейса вашего веб-приложения.

Во внешнем интерфейсе вашего веб-приложения создайте кнопку, при нажатии которой инициируется поток OAuth 2.0, перенаправляя пользователей в Google, чтобы они могли войти в систему и предоставить веб-приложению доступ к своей учетной записи Google. Обработчик кнопки должен содержать следующую логику:

// the client id from GCP
const client_id = ""

// create a CSRF token and store it locally
const state = crypto.randomBytes(16).toString("hex");
localStorage.setItem("latestCSRFToken", state);
    
// redirect the user to Google
const link = `https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/cloud-platform&response_type=code&access_type=offline&state=${state}&redirect_uri=${window.location.origin}/integrations/google/oauth2/callback&client_id=${client_id}`;
window.location.assign(link);

Здесь мы генерируем токен CSRF, который будет сохранен в локальном хранилище и отправлен в GCP в качестве параметра state; это связано с смягчением атаки межсайтовой подделки запросов (CSRF), которая выходит за рамки этой статьи.

Обратите внимание, что вам следует заменить redirect_uri в link на тот, который вы зарегистрировали на шаге 3 в GCP. Когда пользователи нажимают кнопку, они должны быть перенаправлены в Google, как показано ниже:

6. Проверьте параметр state при перенаправлении пользователя обратно в веб-приложение и отправьте code на серверную часть.

Поскольку Google перенаправит пользователя обратно на redirect_uri после того, как он войдет в систему и предоставит веб-приложению доступ к своей учетной записи Google, вам необходимо создать для него страницу для обработки следующей части потока OAuth 2.0. Здесь redirect_uri будет иметь параметры code и state; вам следует проанализировать эти параметры из URL-адреса и убедиться, что параметр state соответствует токену CSRF в локальном хранилище из шага 4. Если все в порядке, вы можете приступить к отправке code в серверную часть веб-приложения для выполнения обмена code-token.

const { code, state } = queryString.parse(router.asPath.split("?")[1]);

// validate the state parameter
if (state !== localStorage.getItem("latestCSRFToken") {
  localStorage.removeItem("latestCSRFToken");
  // send the code to the backend
  const res = await axios.post("/api/oauth-token", {
    code
  });
}

7. Обменяйте code на access_token и refresh_token .

Теперь в серверной части вашего приложения вам следует выполнить обмен токенами кода с конечной точкой API Google.

const res = await axios.post(
  "https://oauth2.googleapis.com/token",
  new URLSearchParams({
    grant_type: "authorization_code",
    code,
    client_id: process.env.GCP_CLIENT_ID,
    client_secret: process.env.GCP_CLIENT_SECRET,
    redirect_uri: `your-domain/integrations/gcp-secret-manager/oauth2/callback`,
  })
);

const access_token = res.data.access_token; // used to access the Google API
const refresh_token = res.data.refresh_token; // used to refresh the access token
const expires_in = res.data.expires_in; // used to know when to refresh the access token

8. Используйте access_token для доступа к Google API от имени пользователя.

Теперь вы можете получить доступ к API Google от имени пользователя, включив access_token в запросы к API.

9. Если срок действия access_token истечет, активируйте refresh_token, чтобы получить новый access_token .

На шаге 7 вы, возможно, заметили, что GCP возвращает два дополнительных поля, которые мы привязываем к переменным refresh_token и expires_in. Поскольку access_token — это учетные данные для аутентификации Google API с коротким сроком действия, поле expires_in помогает нам сообщить, когда истечет срок их действия. Как только мы узнаем, что срок действия токена доступа истек, мы можем сделать специальный запрос API, содержащий refresh_token, к конечной точке токена, чтобы получить новый access_token и продолжить доступ к API Google от имени пользователя, как на шаге 8.

const res = await standardRequest.post(
  "https://oauth2.googleapis.com/token",
  new URLSearchParams({
    client_id: process.env.GCP_CLIENT_ID,
    client_secret: process.env.GCP_CLIENT_SECRET,
    refresh_token,
    grant_type: "refresh_token",
  })
);

const access_token = res.data.access_token;
const expires_in = res.data.expires_in;

Вот и все!

Теперь вы знаете, как настроить свое приложение для аутентификации с помощью API Google с использованием OAuth 2.0.

Советы

Правильная реализация OAuth 2.0 имеет решающее значение для безопасности вашего приложения и пользователей.

Вот несколько практических советов, которые вам следует иметь в виду:

  • Не записывайте Идентификатор клиента и Секрет клиента для своего приложения где-либо в базе кода. Вместо этого вам следует безопасно хранить как Идентификатор клиента, так и Секрет клиента вашего приложения, предпочтительно в виде переменных среды приложения. Более того, вам следует рассмотреть возможность хранения этих учетных данных в секретном менеджере, таком как Infisical, и возвращать их обратно на сервер во время выполнения.
  • Не выполняйте обмен кодом-токеном OAuth несколько раз. Обмен должен выполняться один раз, после чего вам следует управлять токенами обновления и доступа для выполнения всех последующих запросов к API службы. Поскольку с этими токенами следует обращаться безопасно, как и в моем предыдущем совете, вам также следует рассмотреть возможность хранения их в секретном менеджере.

— -

Infisical — платформа управления секретами с открытым исходным кодом.

Infisical (9,4 тыс.+ ⭐️) помогает тысячам команд и организаций хранить и синхронизировать секреты внутри своей команды и инфраструктуры.

Репозиторий GitHub: https://github.com/Infisical/infisical