6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

OIDC RP を実装する場合以下のようなことをする必要があります。
※ 認可コードグラントです。

  • ディスカバリ構成の管理
  • 認可エンドポイントの生成
  • トークンエンドポイントへのアクセス
  • トークンの検証

etc ...

OIDC はカッチリ仕様が決まっていますし、そこまで複雑な実装にもならないと思いますが、ライブラリがあるなら頼りたいものです。
本記事では Go で OIDC RP をライブラリを用いて実装するにあたり候補となるライブラリを調査し実際に使ってみたのでご紹介します。

ライブラリ

調べたところ候補となるライブラリは以下の2つがありました。
(ほかにもあったら教えていただきたいです。)

どちらもライセンスは Apache-2.0 license です。

本記事執筆で参照しているそれぞれのライブラリのバージョンは

です。

実装フロー

今回ライブラリを使ってみるにあたり実装したフローは以下となります。
説明のため、一部パラメータなどを省略しているので正確なものではありません。
ご了承ください。

Go によるサーバーでの Relying Party の実装なので noncePKCE は利用しません。
(あと、この方がよりシンプルに説明できるのかなと思っています。)

OpenAPI でエンドポイントを定義して利用します。
サーバーの実装をサボるために ogen による自動生成を活用しています。

準備

実際に動作確認を実施するにあたり Google と連携します。

こちらのドキュメントを参考にプロジェクトを用意しています。

coreos/go-oidc

coreos/go-oidc は以下に示すように example が用意されています。

パッケージインポート

import(
	"github.com/coreos/go-oidc/v3/oidc"
	"golang.org/x/oauth2"
)

初期化処理

一連の処理にて oidc.Provideroauth2.Config という構造体が必要となります。

ctx := context.Background()

provider := oidc.NewProvider(ctx, "issuer")

config := &oauth2.Config{
    ClientID:     "client_id",
	ClientSecret: "client_secret",
	Endpoint:     provider.Endpoint(),
	RedirectURL:  "redirect_url",
	Scopes:       []string{oidc.ScopeOpenID}
}

認可エンドポイント生成処理

// GET /auth へのアクセス

endpoint := config.AuthCodeURL("state")

// 上記で生成したエンドポイントにリダイレクトされるようにクライアントに返す

トークン取得処理

//  GET /callback へのアクセス

token, _ := config.Exchange(ctx, "code")

idToken, _ := token.Extra("id_token").(string)

IDトークン検証処理

if _, err := provider.Verifier(&oidc.Config{
    ClientID: "client_id"
}).Verify(ctx, idToken); err != nil {
    panic(err)
}

zitadel/oidc

zitadel/oidc でも以下に示すように example が用意されています。

こちらのサンプルコードでは処理を http.HandleFunc() へと渡す形式で実装されています。
が、ogen などのライブラリを活用して実装する場合だと参考になりません。
コードを漁っていると他の方法でも OIDC RP としての処理を記述できることがわかったのでそちらの方法で実装します。

パッケージインポート

import (
	"github.com/zitadel/oidc/v3/pkg/client/rp"
	"github.com/zitadel/oidc/v3/pkg/oidc"
)

初期化処理

一連の処理にて構造体 rp.RelyingParty が必要となります。

ctx := context.Background()

provider, _ := rp.NewRelyingPartyOIDC(
	ctx,
	"issuer",
	"client_id",
	"client_secret",
	"redirect_uri",
	[]string{"openid"},
)

認可エンドポイント生成処理

// GET /auth へのアクセス

endpoint := rp.AuthURL("state", provider)

// 上記で生成したエンドポイントにリダイレクトされるようにクライアントに返す

トークン取得処理

//  GET /callback へのアクセス

token, _ := rp.CodeExchange[*oidc.IDTokenClaims](ctx, "code", provider)

idToken, _ := token.Extra("id_token").(string) // coreos と同じ処理

IDトークン検証処理

if _, err := rp.VerifyIDToken[*oidc.IDTokenClaims](ctx, idToken, provider.IDTokenVerifier()); err != nil {
	panic(error)
}

おわりに

どちらのライブラリを使っても省エネルギーで OIDC RP の実装ができるなと確認できました。
正直どちらも使用感は変わらなかったですが、zitadel のほうが rp.RelyingParty という構造体の管理で一連の処理が記述できる点は良いと感じました。

zitadel/oidc に以下のような記載があったりするので個人的にはこちらのライブラリを使っていこうと思います。

Easy to use OpenID Connect client and server library written for Go and certified by the OpenID Foundation

複数プロバイダーや複数のコールバックURIを管理するときの実装をいい感じにするためにはどうしようかなと迷っています ...

今回実装したコードは以下に置いておきます。ご参考まで。

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?