💽

Remix with Okta

2024/12/12に公開

この記事は GENDA Advent Calendar 2024 12日目の記事です。

https://qiita.com/advent-calendar/2024/genda

はじめに

GENDAでは今年からOktaが導入されました。
今回は、Oktaを導入によってできそうなこと、試したことをご紹介したいと思います。
導入の背景だったりは 10日目の kenshiro さんの記事で詳しく説明されております。

https://zenn.dev/kenshiro/articles/70abe2faee637b

これまで

複数の会社がグループしていく中で大変なのが、各種管理画面だったり複数組織にまたがるID・権限管理です。各プロダクトそれぞれでログイン機能が実装されていたり、VPNで制御されているものがほとんどですが、今後も増え続けるであろう社内アプリケーションでのID管理の仕組みをどうにかできないかなと考えていました。

できそうなこと、試したこと

Oktaが会社全体(グループも含めた)で統一されたアイデンティティ及びアクセス管理として使うことが可能になったら上記の問題も解決できる且つ運用もとても楽にできそうと思っています。

今回は、Okta で提供されている OpenID Connect & OAuth 2.0 API を用いてログインできるWebページを作成していきたいと思います。

社内の管理画面でもよく採用される Remix(ReactRouter) を用います。
https://github.com/sergiodxa/remix-auth-oauth2
こちらのライブラリを用いると、OAuth2に対応するストラテジを実装するだけで済みそうです。

import { OAuth2Strategy } from 'remix-auth-oauth2'

export type OktaProfile = {
  sub: string
  name: string
  given_name: string
  family_name: string
  email: string
  email_verified: boolean
}

if (!process.env.OKTA_CLIENT_ID || !process.env.OKTA_CLIENT_SECRET) {
  throw new Error('OKTA KEY is required')
}

if (!process.env.OKTA_CALLBACK_URL) {
  throw new Error('CALLBACK URL is required')
}

const OKTA_ENDPOINT = process.env.OKTA_ENDPOINT
export const oktaOauth2Strategy = new OAuth2Strategy(
  {
    clientId: process.env.OKTA_CLIENT_ID,
    clientSecret: process.env.OKTA_CLIENT_SECRET,
    authorizationEndpoint: `${OKTA_ENDPOINT}/oauth2/v1/authorize`,
    tokenEndpoint: `${OKTA_ENDPOINT}/oauth2/v1/token`,
    redirectURI: process.env.OKTA_CALLBACK_URL,

    scopes: ['openid', 'email', 'profile'], // optional
  },
  async ({ tokens, profile }) => {
    console.log('LOG FROM AUTH OKTA STRATEGY')
    console.log({ tokens, profile })

    const userInfo: {
      sub: string
      name: string
      given_name: string
      family_name: string
      email: string
      email_verified: boolean
    } = await fetch(`${OKTA_ENDPOINT}/oauth2/v1/userinfo`, {
      headers: {
        Authorization: `${tokens.token_type} ${tokens.access_token}`,
      },
    }).then((response) => response.json())

    // ref: https://developer.okta.com/docs/api/openapi/okta-oauth/oauth/tag/OrgAS/#tag/OrgAS/operation/userinfo
    console.log('User Info:')
    console.log(userInfo)

    // return the object that can be used by authenticator objects in `auth.server.ts`
    return {
      sub: userInfo.sub,
      name: `${userInfo.family_name} ${userInfo.given_name}`,
      email: userInfo.email,
      email_verified: userInfo.email_verified
    } as OktaProfile
  },
)

今回は、詳細なプロフィール情報も取得したかったので、Access Token を使用してリソースサーバーにアクセスまで試しました。
これで一応実装はできましたが、IDトークンの検証や nonce パラメータは使用なくていいんだっけ?だったりそもそもOpenID Connect用のストラテジを使用するべきでは?のようなことは社内の有識者と議論・検証していきたいと思います。

これから

今回は、Remix (ReactRouter)に組み込みことで実現しましたが、AWSやGoogleCloudのALBに組み込むことで容易に既存の運用しているWebアプリケーションをOkta対応させることができそうと思っています。(Remixでは、環境に依存しないで実装できることはメリットだとは思ってはいます)
また、Okta では SPAやMobile用の認証フロー用に PKCE OAuth 2.0 flow もサポートされているのでこちらも試してみたいと思います。

⚠️ remix-auth, remix-auth-oauth2 などのライブラリが大型にアップデートされ破壊的な変更がされているのでご注意です

GENDA

Discussion