🗝️

Honoで雑にOAuth2の流れを理解する

2024/09/01に公開

概要と経緯

Honoじゃなくてもなんでも良いのですが、js環境でOAuth2をライブラリなしで動かしたく、とりあえずどこかに備忘録として置いておきたかったという話です。
GoogleのOAuth2で試しました。

免責ですが、雑ゆえにエラーなど全く考慮していません。流れの確認以外には使えないコードであるとご了承ください。

おおまかな流れ

  1. 認可リクエストを送信
  2. リダイレクトURLに code が返ってくるので、それでアクセストークンを取得する
  3. 試しに userinfo とか取得してみる

1. 認可リクエストの送信

事前に取得しておいた client_id redirect_uri で認可リクエストを送信(リダイレクト)します。
http://localhost:3000/auth/login へ遷移するとGoogleでのログインプロセスに飛びます。

const CLIENT_ID = "XXXXXXXX.apps.googleusercontent.com";
const CLIENT_SECRET = "XXXXXXXXXX";
const REDIRECT_URI = "http://localhost:3000/auth/callback";

app.get("/auth/login", (c) => {
  const url = "https://accounts.google.com/o/oauth2/v2/auth";
  const params = new URLSearchParams({
    client_id: CLIENT_ID,
    redirect_uri: REDIRECT_URI,
    response_type: "code",
    scope: "email profile",
  });

  return c.redirect(`${url}?${params}`);
});

2. アクセストークンを取得する

リダイレクトURIに code パラメータ付きでリダイレクトされるので、その code を使ってアクセストークンを取得します。
取得できたアクセストークンは、とりあえず雑に cookie に焼いておきます。

app.get("/auth/callback", async (c) => {
  const params = new URLSearchParams({
    code: c.req.query("code") || "",
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET,
    redirect_uri: REDIRECT_URI,
    grant_type: "authorization_code",
  });
  // アクセストークンを取得する
  const res = await fetch("https://oauth2.googleapis.com/token", {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded",
    },
    body: params.toString(),
  });
  const data = await res.json();
  // アクセストークンはとりあえずcookieに焼いておく
  if (data.access_token) {
    setCookie(c, "token", data.access_token, {
      httpOnly: true,
      secure: true,
    });
  }
  // /hello に飛ばしてそっちで動作確認しよう
  return c.redirect("/hello");
});

3. 試してみよう

もらったアクセストークンを使って userinfo の取得など試してみます。 Authorization ヘッダーにアクセストークンを付与します。

app.get("/hello", async (c) => {
  const token = getCookie(c, "token");
  const url = "https://www.googleapis.com/oauth2/v1/userinfo";
  const res = await fetch(url, {
    headers: {
      Authorization: `Bearer ${token}`,
    },
  });
  const data = await res.json();
  return c.json(data);
});

悩みポイント

  • アクセストークンを取得するURLの公式情報がなかなか見つけられず、各記事で記載されているURLもバラバラだったため、 OAuth 2.0 Playground で確認をした。

Discussion