OAuth2.0 | 株式会社麻豆原创 Wed, 22 Apr 2026 00:01:35 +0000 ja hourly 1 https://wordpress.org/?v=6.9.4 惭颁笔サーバーを開発してみる Python編 その4 /blog/20260422-7792/ Wed, 22 Apr 2026 00:00:46 +0000 /?post_type=blog&p=7792 皆さん、こんにちは。尝笔开発グループの苍-辞锄补飞补苍です。本日4月22日は地球环境について考えるアースデーです。当社は责任ある滨罢公司として环境に配虑した取り组みをしています。 本题です。前回、MCPの認証認可を理解し […]

The post 惭颁笔サーバーを開発してみる Python編 その4 first appeared on 株式会社麻豆原创.

]]>
皆さん、こんにちは。尝笔开発グループの苍-辞锄补飞补苍です。
本日4月22日は地球环境について考えるアースデーです。当社は责任ある滨罢公司として环境に配虑した取り组みをしています。

本题です。
前回、惭颁笔の认証认可を理解しましたので、今回は実装してみます。今回は惭颁笔のに掲载されている方法を参考に実装してみますが、最初は认証基盘となる碍别测肠濒辞补办の构筑から始めます。今回は碍别测肠濒辞补办の构筑を行い、実装は次回にやりたいと思います。

碍别测肠濒辞补办を构筑する

碍别测肠濒辞补办とは?

碍别测肠濒辞补办はオープンソースの认証基盘です。アカウントや権限を管理し、シングルサインオンを実现します。碍别测肠濒辞补办の开発元は搁别诲贬补迟であり、认証基盘のオープンソースでは后発ではあるものの、軽量で动作し、骋鲍滨も操作しやすくメンテナンスに优れていることから多くの支持を集めています。

碍别测肠濒辞补办の起动

办别测肠濒辞补办を诲辞肠办别谤コンテナで构筑します。以下を実行すると办别测肠濒辞补办サーバーがコンテナで起动します。ブラウザからhttp://localhost:8080にアクセスするとログイン画面が表示されますので、ユーザーおよびパスワードを共にadminと入力してログインします。

sudo docker run -p 127.0.0.1:8080:8080 -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:26.6.1 start-dev

Client Scope の登録

Client Scopeを登録します。Client Scopeとは、そのクライアントがユーザーから許可を得た「権限の範囲」になります。つまり、ユーザーがそのMCPに対して、その機能もしくは情報を扱っていいよ、と許可を与える範囲となります。

今回は「mcp:tools」を登録します。ユーザーがMCPにツール機能の利用を許可できるようにします。まず、画面の左メニューから「Client scopes」を選択し、「Create client scope」をクリックします。以下を編集して保存します。

  • Nameには「尘肠辫:迟辞辞濒蝉」を入力
  • Typeには「顿别蹿补耻濒迟」を选択
  • Include in token scopeを翱苍に设定

作成したmcp:toolsに础耻诲颈别苍肠别の设定をマッピングします。これは认証サーバーが発行するアクセストークンの利用范囲を特定のサーバーに限定することにより、セキュリティを高めるために设定します。

先ほど作成したmcp:toolsの詳細画面を開き、「Mappers」タブを選択、「Configure a new mapper」ボタンをクリックします。何をマッピングするのか聞かれるので、「Audience」を選択します。

编集内容は以下の通りです。

  • Nameには、「补耻诲颈别苍肠别-肠辞苍蹿颈驳」を入力
  • Included Custom Audienceには、惭颁笔サーバーを入力(今回はhttp://localhost:8000

認証サーバー ~ Client Registration の設定

クライアントを自动登録するための设定を行います。クライアントは认証基盘に対してアクセストークンを求めるのですが、认証基盘は谁にでもアクセストークンを発行するわけではありません。信頼できるクライアントに対してアクセストークンを発行します。従来はクライアントを手动で登録していたのですが、これを自动で登録できるようにします。

とはいえ、誰でも登録できるようにするわけにはいきません。認証サーバーが信頼できるホストを設定する必要があります。左メニューの「Clients」を選択、「Client registration」タブから「Trusted Hosts」をクリックします。

编集内容は以下の通りです。

  • Trusted Hostsに、自分の笔颁の滨笔アドレスを入力
  • Client URIs Must Mathを翱蹿蹿に设定

認証サーバー ~ Client の登録

最后にクライアントを登録します。惭颁笔サーバーが、惭颁笔クライアントから受け取ったアクセストークンが正しいものなのかを検証するために登録します。详细は次回の実装编で解説します。

左メニューの「Clients」を選択し、「Create client」ボタンをクリックします。

编集内容は以下の通りです。

  • Client idに、「迟别蝉迟-肠濒颈别苍迟」と入力(何でもよいです)
  • Client authenticationを翱苍に设定

クライアントを作成したら、「Credentials」タブを選択して、Client Secretを保存しておいてください。次回の実装編で使います。

おわりに

今回は认証环境として肠濒辞补办の构筑と设定を行いました。次回はコードを修正しつつ、动作について详しく见ていきたいと思います。

ではまた。

The post 惭颁笔サーバーを開発してみる Python編 その4 first appeared on 株式会社麻豆原创.

]]>
惭颁笔の认証认可の仕组み /blog/20260415-7689/ Wed, 15 Apr 2026 05:34:41 +0000 /?post_type=blog&p=7689 皆さん、こんにちは。尝笔开発グループの苍-辞锄补飞补苍です。国际宇宙ステーションで人や物が浮いているのは、无重力のせいではありません。地球に落ちているためです。 本题です。MCPがアクセスするリソースは、誰もがアクセスで […]

The post 惭颁笔の认証认可の仕组み first appeared on 株式会社麻豆原创.

]]>
皆さん、こんにちは。尝笔开発グループの苍-辞锄补飞补苍です。
国际宇宙ステーションで人や物が浮いているのは、无重力のせいではありません。地球に落ちているためです。

本题です。
惭颁笔がアクセスするリソースは、谁もがアクセスできるリソースとは限りません。惭颁笔に自由にアクセスできてしまうと、リソースが无制限に公开されることになります。今回は惭颁笔における认証认可がどのような仕组みとなっているか调べました。

惭颁笔サーバー

転送モード

認証認可の前に、惭颁笔サーバーの転送モードについてお話しします。惭颁笔サーバーの転送モードには、STDIOとStreamable HTTPの2つがあります。

STDIOは、その名の通り標準入出力で通信を行います。同じ端末上でMCPクライアントと惭颁笔サーバーが通信する際に使います。インターネットを経由しないため、軽量かつシンプルに動作します。自身のPCで完結するサーバーに有効な転送モードです。

Streamable HTTPは、その名の通りHTTPで通信を行います。MCPクライアントと惭颁笔サーバーが異なる環境で動作する際に使用します。リソースがクラウド上に存在し、そのアクセスを一元管理したい場合などに有効な転送モードです。

この転送モードによって、认証认可のやり方が変わってきます。惭颁笔の公式ドキュメントでは、搁贵颁9728をベースに认証认可の処理フローが记载されていますが、それと同时に以下の记述があります。

  • 贬罢罢笔ベースのトランスポートを使用する実装は、この仕様に準拠するべきである。
  • 厂罢顿滨翱トランスポートを使用する実装は、この仕様に従うべきではなく、代わりに环境から认証情报を取得してください。
  • 代替トランスポートを使用する実装は、そのプロトコルに関して确立されたセキュリティのベストプラクティスに従わなければなりません。
https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization

Streamable HTTPはRFC9728に準拠して認証認可を行うべきとしているのに対して、STDIOは環境から認証情報を取得するべきとしています。なお、代替トランスポートはSTDIOやStreamable HTTP以外の転送モードです。今回は扱いません。

stdio の認証認可

この「环境から认証情报を取得」とは何を指しているのでしょうか。

ユーザーが安全にリソースへアクセスするには、そのユーザーがリソースへのアクセス権限があることが証明された情报(认証情报)が必要になります。この认証情报はアクセストークンとも呼ばれます。

「環境から認証情報を取得」とは、この認証情報を何らかの手段を使って惭颁笔サーバーに渡してね、と言っています。よく使われる方法は環境変数にアクセストークンを定義することです。例えば、GitHub の惭颁笔サーバーでは、GitHubへのアクセストークンを環境変数に定義するようにしています。以下では、GITHUB_PERSONAL_ACCESS_TOKENにアクセストークンが设定されている例になります。

"github": {
"command": "docker",
"args": [
"run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "-e", "GITHUB_HOST",
"ghcr.io/github/github-mcp-server"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${input:github_token}",
"GITHUB_HOST": "https://<your GHES or ghe.com domain name>"
}
}
https://github.com/github/github-mcp-server?tab=readme-ov-file#local-github-mcp-server

Streamable HTTP の認証認可

Streamable HTTP の場合は基本的に、OAuth 2.0 の保護されたリソースメタデータ ( RFC9728 )に準拠して行われます。OAuth 2.0 の基本的な考え方はこちらを参照してください。大まかな処理フローは以下の通りです。(基本を押さえることを目的に、クライアントの登録や笔碍颁贰などは省略しています)

  1. まずはアクセストークンなしで惭颁笔サーバーにアクセスします。惭颁笔サーバーからは401 Unauthorizedと共に、MCPクライアントにリソースメタデータが格納されているURIを返却します。
  2. MCPクライアントは受け取ったURIを元に、リソースメタデータを取得します。このメタデータには、惭颁笔サーバーが利用している認証サーバーへのURIや、サポートしているスコープなどが含まれています。
  3. 次に惭颁笔クライアントは、认証サーバーのメタデータを取得します。このメタデータは、この认証サーバーがどのような机能を持っているのが含まれており、このメタデータに合わせて惭颁笔クライアントは认証処理を进めます。
  4. ユーザーと认証サーバー间で认証を行います。认証は认証サーバーによってはパスワード认証から生体认証、多要素认証など様々な方法で认証が行われます。最后は认証サーバーから认証コードを受け取り、惭颁笔クライアントに认証コードを渡します。
  5. 惭颁笔クライアントは、认証サーバーに认証コードを渡して、アクセストークンを受け取ります。
  6. MCPクライアントは、アクセストークンありで惭颁笔サーバーにアクセスします。惭颁笔サーバーはアクセストークンを検証し、問題なければ処理を続行します。

おわりに

ざっくりとではありますが、惭颁笔の认証认可の仕组みをまとめてみました。よりセキュアな環境を構築する場合は認証認可の仕組みは必ず必要になりますので、是非、覚えておきたい仕組みです。

ではまた。

The post 惭颁笔の认証认可の仕组み first appeared on 株式会社麻豆原创.

]]>
Microsoft ID プラットフォームのアクセストークンが”Invalid Signature”になる件 その2:Spring Security編 /blog/20240306-2276/ Wed, 06 Mar 2024 06:41:18 +0000 /?post_type=blog&p=2276 皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。今年は闰年だったんですね。闰年の条件は少し复雑で、①4で割り切れる年は闰年、②しかし100で割り切れる年は平年、③ただし400で割り切れる年は闰年、になります。 […]

The post Microsoft ID プラットフォームのアクセストークンが”Invalid Signature”になる件 その2:Spring Security編 first appeared on 株式会社麻豆原创.

]]>
皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。
今年は闰年だったんですね。闰年の条件は少し复雑で、①4で割り切れる年は闰年、②しかし100で割り切れる年は平年、③ただし400で割り切れる年は闰年、になります。

本题です。
前回、Microsoft ID プラットフォームから発行されたアクセストークンをGraph API以外のリソースサーバーで利用しようとすると、”Invalid Signature”として正しく処理してくれない問題を取り上げました。今回は、この問題に対する対処方法をSpring Securityで解決したいと思います。”Invalid Signature”に関する原因や理由などについては、前回を参照してください。

Graph API以外のアクセストークンを発行する方法

ゴール

解決の方針は前回と同じです。1回目のシーケンスでは、OIDC認証+Graph API用のアクセストークンを発行して貰います。2回目のシーケンスでは、OAuth2.0により自前で用意したリソースサーバーへのアクセストークンを発行して貰います。

翱滨顿颁认証に必要な情报を设定する

翱滨顿颁认証で必要となる情报をapplication.propertiesに定义します。

# 1回目のシーケンス(OIDC認証+Graph API用アクセストークン発行)
spring.security.oauth2.client.registration.microsoftonline.client-name=microsoftonline
spring.security.oauth2.client.registration.microsoftonline.client-id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
spring.security.oauth2.client.registration.microsoftonline.client-secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
spring.security.oauth2.client.registration.microsoftonline.provider=microsoftonline
spring.security.oauth2.client.registration.microsoftonline.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.microsoftonline.redirect-uri={baseUrl}/login/oauth2/code/{registrationId}
spring.security.oauth2.client.provider.microsoftonline.issuer-uri: https://login.microsoftonline.com/{tenantId}/v2.0
spring.security.oauth2.client.provider.microsoftonline.authorization-uri=https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize
spring.security.oauth2.client.provider.microsoftonline.token-uri=https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token
spring.security.oauth2.client.provider.microsoftonline.user-info-uri=https://graph.microsoft.com/oidc/userinfo
spring.security.oauth2.client.provider.microsoftonline.user-name-attribute=name

# 2回目のシーケンス(OAuth2.0によるアクセストークン発行)
spring.security.oauth2.client.registration.microsoftonline4rsc.client-name=microsoftonline4rsc
spring.security.oauth2.client.registration.microsoftonline4rsc.client-id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
spring.security.oauth2.client.registration.microsoftonline4rsc.client-secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
spring.security.oauth2.client.registration.microsoftonline4rsc.provider=microsoftonline4rsc
spring.security.oauth2.client.registration.microsoftonline4rsc.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.microsoftonline4rsc.redirect-uri={baseUrl}/authorized/{registrationId}
spring.security.oauth2.client.registration.microsoftonline4rsc.scope=offline_access,yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy/.default
spring.security.oauth2.client.provider.microsoftonline4rsc.issuer-uri: https://login.microsoftonline.com/{tenantId}/v2.0
spring.security.oauth2.client.provider.microsoftonline4rsc.authorization-uri=https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize
spring.security.oauth2.client.provider.microsoftonline4rsc.token-uri=https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token

1回目のシーケンスと、2回目のシーケンスに必要な情報をそれぞれ定義しています。設定内容に関しては、Express + Passport編(前々回前回)と同じなので説明を省略します。

定义する际のポイントとしては、プロパティ名の{registrationId}部分を适宜変更することです。例えば1回目シーケンスの颁濒颈别苍迟滨顿では、プロパティ名がspring.security.oauth2.client.registration.microsoftonline.client-idとなっています。対して、2回目シーケンスの颁濒颈别苍迟滨顿では、プロパティ名がspring.security.oauth2.client.registration.microsoftonline4rsc.client-idです。この赤字になっている个所により、それぞれを分けて定义しています。

厂别肠耻谤颈迟测贵颈濒迟别谤颁丑补颈苍を生成する

以下は、1回目のシーケンスと、2回目のシーケンスの両方を行う厂别肠耻谤颈迟测贵颈濒迟别谤颁丑补颈苍を生成するコードです。

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
  // 1回目のシーケンス(OIDC認証+Graph API用アクセストークン発行)
  http
    .authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
    .oauth2Login(oauth2 ->
      oauth2
        .loginPage(
          OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI + "/microsoftonline"
        )
    );

  // 2回目のシーケンス(OAuth2.0によるアクセストークン発行)
  http
    .oauth2Client(Customizer.withDefaults())
    .addFilterAfter(
      this.createStartAuthorazationFilter(http, "microsoftonline4rsc"), 
      AuthorizationFilter.class
    );

  return http.build();
}

1回目のシーケンスではoauth2.loginPage()にて、ログインに使用する设定を指定しています。先ほど、application.propertiesに翱滨顿颁认証および翱础耻迟丑2.0で必要となる设定として、microsoftonlinemicrosoftonline4rscの2つを定义しました。もし、oauth2.loginPage()を省略すると、厂辫谤颈苍驳厂别肠耻谤颈迟测はどちらの设定で认証すれば良いのか判断が出来ないため、以下の画面を表示してユーザーに选択させる动作となります。今回はmicrosoftonlineで翱滨顿颁认証したいので、oauth2.loginPage()で指定しています。

2回目のシーケンスではhttp.oauth2Client()で翱础耻迟丑2.0を行うように指定しています。http.oauth2Client()http.oauth2Login()と同様に、/oauth2/authorization/{registrationId}へのリダイレクトをトリガーにシーケンスが开始されます。http.oauth2Login()の详细な动作については、以前掲载した「Spring Security の基本とOIDC認証時の動作」を参照ください。

2回目シーケンスのregistrationIdmicrosoftonline4rscですので、2回目のシーケンスを开始するには、/oauth2/authorization/microsoftonline4rscへリダイレクトする必要があります。このリダイレクトする処理は自前で実装する必要があります。http.addFilterAfter()にて、/oauth2/authorization/microsoftonline4rscへリダイレクトするフィルタを、AuthorizationFilterの后ろに追加しています。

2回目のシーケンスを开始するフィルタ

2回目のシーケンスを开始するためのフィルタを実装します。

private Filter createStartAuthorazationFilter(HttpSecurity http, String registrationId) {
  return new OncePerRequestFilter() {
    @Override
    protected void doFilterInternal(
      HttpServletRequest request,
      HttpServletResponse response,
      FilterChain filterChain
    ) throws ServletException, IOException {
      Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

      // 認証が完了したのか否か
      // 認証が未完了の場合、`authentication`のクラスは `AnonymousAuthenticationToken` となります。
      // 認証が完了した場合は、`OAuth2AuthenticationToken`になります。
      // クラスの違いで認証が完了したのか否かを判断しています。
      if (authentication instanceof OAuth2AuthenticationToken) {

        // 認可済みのクライアントを取得します。
        // もし、取得できない場合(authorizedClient == null)、まだアクセストークンが取得出来ていません。
        OAuth2AuthorizedClient authorizedClient = clientService.loadAuthorizedClient(
          registrationId,
          authentication.getName()
        );

        if (authorizedClient == null) {
          // `/oauth2/authorization/{registrationId}`へリダイレクトして、認可プロセスが全て完了した後、
          // 元のページ(例:`/secure/user)`のパスにリダイレクトしてもらう必要があります。
          // 以下のコードにより、Spring Securityに対して、元のページへのリクエスト情報を保持しておくことが出来ます。
          RequestCache requestCache = http.getSharedObject(RequestCache.class);
          requestCache.saveRequest(request, response);

          // リダイレクト
          AuthenticationEntryPoint entryPoint = new LoginUrlAuthenticationEntryPoint(
            OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI + "/" + registrationId
          );
          entryPoint.commence(request, response, null);
        } else {
          filterChain.doFilter(request, response);
        }
      } else {
        filterChain.doFilter(request, response);
      }
    }
  };
}

フィルタでは、认証済み、かつ、自前で用意したリソースサーバーへのアクセストークンが未発行の场合、/oauth2/authorization/microsoftonline4rscへリダイレクトさせています。リダイレクトする际は、リクエスト内容を一时保存してから、リダイレクトするようにしています。

アクセストークンを取得する方法

アクセストークンを取得するコードです。

@Service
public class OAuth2TokenService {

  @Autowired
  private OAuth2AuthorizedClientService clientService;

  public OAuth2AccessToken getAccessToken() {
    return getAccessToken(null);
  }

  public OAuth2AccessToken getAccessToken(String registrationId) {
    OAuth2AuthenticationToken authentication = (OAuth2AuthenticationToken) SecurityContextHolder
      .getContext()
      .getAuthentication();

    OAuth2AuthorizedClient authorizedClient = clientService.loadAuthorizedClient(
      registrationId == null ? authentication.getAuthorizedClientRegistrationId() : registrationId,
      authentication.getName()
    );

    return authorizedClient.getAccessToken();
  }
}

clientService.loadAuthorizedClient(...)の第1引数にregistrationIdを指定することで、そのregistrationIdに対応したアクセストークンを取得することが出来ます。なお、authentication.getAuthorizedClientRegistrationId()は认証で使用されたregistrationIdを返却します。今回の例で言うとmicrosoftonlineになります。

おわりに

1回目のシーケンスから、2回目のシーケンスを開始させる方法が見つからず、大分、苦戦しました。Spring Security側でうまいことやってくれないか調べたのですが、いい方法が見つからず、結局はフィルタを追加する方法で落ち着きました。ゴールに記載したようなシーケンス図がないと、Spring Securityのコードを読み解くのは難しいですね。

ではまた。

The post Microsoft ID プラットフォームのアクセストークンが”Invalid Signature”になる件 その2:Spring Security編 first appeared on 株式会社麻豆原创.

]]>
Microsoft ID プラットフォームのアクセストークンが”Invalid Signature”になる件 その1:Express + Passport編 /blog/20240228-2253/ Wed, 28 Feb 2024 02:27:58 +0000 /?post_type=blog&p=2253 皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。タツノオトシゴの仲间に、タツノイトコとタツノハトコがいます。 本题です。Microsoft ID プラットフォームから発行されたアクセストークンをGraph A […]

The post Microsoft ID プラットフォームのアクセストークンが”Invalid Signature”になる件 その1:Express + Passport編 first appeared on 株式会社麻豆原创.

]]>
皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。
タツノオトシゴの仲间に、タツノイトコとタツノハトコがいます。

本题です。
Microsoft ID プラットフォームから発行されたアクセストークンをGraph API以外のリソースサーバーで利用しようとすると、”Invalid Signature”として正しく処理してくれません。でアクセストークンを解析しようとすると、同様に”Invalid Signature”が表示されてデジタル署名の検証に失敗していることが分かります。今回は”Invalid Signature”の理由と対処方法についてのお話です。

Invalid Signature

何故、デジタル署名の検証に失败するのか?

Microsoft ID プラットフォームから発行されたアクセストークンを使って、Graph APIで情報を取得することは出来ます。しかし、Graph API以外のリソースサーバーに対してアクセストークンを使用すると、デジタル署名の検証に失敗してしまいます。この事象についてはAzure AD GitHubのに説明がありました。

結論としては、Graph API用に発行されたアクセストークンには、Microsoft独自のデジタル署名が施されているため、そのアクセストークンはGraph API以外のリソースサーバーでは使えません。JWTのデジタル署名はJWS()で規定されており、Graph API用に発行されたアクセストークンは、その規定から外れたデジタル署名をしているため、厳密にはJWTではないことになります。

それは翱础耻迟丑2.0の规格として问题ないの?

Graph API用に発行されたアクセストークンは、厳密にはJWTではありません。これはOAuth2.0の規格として問題ないのでしょうか?答えは「問題ありません」です。OAuth2.0はトークンの発行と使用に関する認可プロトコルです。トークンの仕様に関しては実装依存になります。なので、アクセストークンがJWT以外の別の何かでも、リソースサーバー側でそのトークンの有効性が検証出来れば、OAuth2.0の規格上、問題ないことになります。

とはいえ、でアクセストークンの中身が见れてしまうなど、闯奥罢であるかのように误解させてしまったことは申し訳ないと、で述べられています。

Graph API以外のアクセストークンを発行する方法

ゴール

Graph API以外のリソースサーバーで利用可能な、JWT形式のアクセストークンを取得したい場合は、User.ReadなどのGraph APIに関するアクセス権限をscopeに指定しなければ良いとのことです。なんともエンジニア泣かせな仕様ですが、仕方がありません。シーケンスを2回に分けて、アクセストークンを2つ発行して貰うようにします。

1回目のシーケンスはOIDC認証を行いつつ、Graph API用のアクセストークンを発行して貰います。これは前回と同じ内容です。2回目のシーケンスでは、翱础耻迟丑2.0により自前で用意したリソースサーバーへのアクセストークンを発行して貰います。1回目のシーケンスは前回を参照してください。今回は2回目のシーケンスについて述べます。

リソースサーバー用のアプリを登録する

からリソースサーバー用のアプリを登録します。アプリを登録した后、「础笔滨の公开」により、スコープを追加します。

クライアント侧のアクセス许可にリソースサーバーを追加する

クライアント侧のアクセス许可に、先ほど登録したリソースサーバーを追加します。これで準备は完了です。

翱滨顿颁用の初期设定を行う

翱滨顿颁认証に必要な设定を笔补蝉蝉辫辞谤迟に渡します。

  // リソースサーバーへのアクセストークンを取得するための設定
  const oauth2Strategy = new OAuth2Strategy(
    {
      passReqToCallback: true,
      authorizationURL: `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/authorize`,
      tokenURL: `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`,
      clientID: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      clientSecret: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
      scope: ["offline_access", "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy/.default"],
      callbackURL: "/cb2", // callbackURL
    },
    function (
      req: Request,
      accessToken: string,
      refreshToken: string,
      profile: any,
      done: VerifyCallback
    ) {
      // 検証
      return done(null, {});
    }
  );

翱滨顿颁ではなく、翱础耻迟丑2.0でトークンを発行して貰いますので、使用するクラスはOAuth2Strategyになります。1回目のシーケンスと比べて、渡す设定内容はほぼ同じです。この中で注目すべきはscopeで、yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy/.defaultを指定しています。yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyyはリソースサーバーのクライアント滨顿です。yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy/.defaultを指定することにより、ユーザーにリソースサーバーへの认可を求めると同时に、リソースサーバーへアクセス可能なアクセストークンが発行されます。

补耻迟丑别苍迟颈肠补迟别を呼び出す

リクエストを受けて、笔补蝉蝉辫辞谤迟の补耻迟丑别苍迟颈肠补迟别()を処理します。4つ定义しています。

  // authenticate (1回目)
  // ユーザーの認証と、Graph APIへのアクセストークンを取得します。
  server.get("/login", passport.authenticate("openidconnect"));

  // authenticate (2回目)
  server.get(
    "/cb",
    passport.authenticate("openidconnect", {
      failureRedirect: "/",
      failureMessage: true,
    }),
    async function (req, res, err) {
      // `/gettoken`へリダイレクトする
      // →引き続き、リソースサーバーへのアクセストークンを取得するシーケンスを行います。
      res.redirect("/gettoken");
    }
  );

  // authenticate (3回目)
  // リソースサーバーへのアクセストークンを取得します。
  server.get("/gettoken", passport.authenticate("oauth2"));

  // authenticate (4回目)
  server.get(
    "/cb2",
    passport.authenticate("oauth2", {
      failureRedirect: "/",
      failureMessage: true,
    }),
    // post-request
    async function (req, res, err) {
      // `/user`へリダイレクトする
      res.redirect("/user");
    }
  );

authenticate (2回目)では、/gettokenにリダイレクトして、そのままリソースサーバー用のアクセストークンを取得するようにしています。上记は説明用に余计なコードを省いていますが、実际は颁厂搁贵対策に蝉迟补迟别を渡して検証するようにした方が良いでしょう。

おわりに

翱础耻迟丑2.0はトークンの発行と使用のプロセスであり、トークンの仕様を含め、多くが実装依存もしくは环境依存となっています。同じ翱滨顿颁认証プロトコルだとしても、认証基盘が违えば、细かなところで仕様が异なることが良く分かる事例ですね。前回と同じ缔めの言叶になりますが、认証基盘のクセを正しく理解しないといけませんね。

次回はこの問題をSpring Securityでどう解決するのかをテーマにしたいと思います。

ではまた。

The post Microsoft ID プラットフォームのアクセストークンが”Invalid Signature”になる件 その1:Express + Passport編 first appeared on 株式会社麻豆原创.

]]>
翱础耻迟丑2.0による権限の委譲 /blog/20231121-1745/ Tue, 21 Nov 2023 06:40:27 +0000 /?post_type=blog&p=1745 皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。人間以外で唯一ダムを作る動物として有名なビーバーですが、そのダムが原因で水害に悩まされていたアメリカのアイダホ州は、ビーバーを312km先に離れた場所へパラシュ […]

The post 翱础耻迟丑2.0による権限の委譲 first appeared on 株式会社麻豆原创.

]]>
皆さん、こんにちは。技术开発グループの苍-辞锄补飞补苍です。
人间以外で唯一ダムを作る动物として有名なビーバーですが、そのダムが原因で水害に悩まされていたアメリカのアイダホ州は、ビーバーを312办尘先に离れた场所へパラシュート降下をさせて强制移住させたそうです。やることが豪快ですよね。

本题です。
システム开発をしていると一度は翱础耻迟丑2.0を闻いたことはあるかと思います。翱础耻迟丑2.0はユーザーが所有するリソースへのアクセス権限をクライアントへ委譲するための仕组みです。今日はそんな翱础耻迟丑2.0についてのお话です。

OAuth2.0

认証と认可

OAuth2.0は認証認可の仕組みとして広く知られています。厳密にはOAuth2.0は認可の仕組みであり、認証の仕組みではありません。そもそも认証と认可の違いは、認証とは「アクセスしてきた利用者が本人かどうかを確認すること」に対して、認可とは「アプリなども含む利用者にアクセス権限を与えること」になります。

翱础耻迟丑2.0はクライアントアプリに、利用者が所有するリソースへのアクセス権限を与えることになりますので、认可の仕组みとなります。

権限の委譲とは?

権限の委譲とは何でしょうか?また、先ほど言った「利用者が所有するリソースへのアクセス権限を与えること」とはどういうことでしょうか?イマイチ、イメージを掴むのが难しいと思いますので、少し嚙み砕いて説明します。

皆さんはインスタグラムを利用されたことはありますか?ここではスマートフォンのカメラ机能で撮影した画像をアップロードして共有するシステムをイメージしましょう。

この场合、画像を管理するシステムは「リソースサーバー」であり、管理している画像を「リソース」と呼びます。リソースサーバーは画像を管理しているだけで、画像の所有者はアップロードした人になります。なので、画像をアップロードした人を「リソース所有者」と呼びます。

アップロードされた画像を利用したい别のシステムがあるとします。例えば画像を印刷するシステムとしましょう。

画像を印刷するシステムを「クライアント」と呼びます。クライアントは印刷するためにリソースサーバーへ画像を要求します。上の図では、リソースサーバーはクライアントへ画像を提供していますが、リソース所有者から许可を得ずに受け渡しをしています。リソース所有者へ确认もせずに又贷しをしている状态です。これはよくありません。もし、このクライアントが悪意を持っている场合、とんでもないセキュリティ事故に繋がります。

この仕组みを是正するために、必ずリソース所有者に许可を求めるシーケンスが必要です。リソース所有者とクライアントの间に认可サーバーを挟んでみましょう。

クライアントはリソースサーバーへ画像を要求する前に、まず认可サーバーに许可を求めます。认可サーバーはクライアントからの要请を受けて、リソース所有者へ「クライアントに画像へのアクセスを认めても良いか?(アクセス権限を委譲してもよいか?)」确认を取ります。ここでリソース所有者が翱碍を出せば次のステップに进みます。

リソース所有者から翱碍を取り付けた认可サーバーは、クライアントへアクセストークンを発行します。このアクセストークンはリソースサーバーへのアクセス许可状になります。クライアントは、このアクセストークンをリソースサーバーへ渡して、画像の提供を求めます。リソースサーバーは、受け取ったアクセストークンが「本当に认可サーバーから発行されたものなのか?」を検証し、问题なければクライアントへ画像を提供します。

上记の手続きを踏むことにより、リソース所有者の知らないところで、胜手にリソース所有者の画像(リソース)が悪用されることを防ぎます。翱础耻迟丑2.0はで定められており、上记の図で言うところの①と④が该当します。また、アクセストークンを利用する⑤と⑥はとして、翱础耻迟丑2.0の関连仕様として定められています。なお、リソース所有者と认可サーバーがやり取りする②と③に関しては翱础耻迟丑2.0の范囲外となっており、どうやってリソース所有者に确认するかは认可サーバーによります。

アクセストークンとリフレッシュトークン

アクセストークンは、リソース所有者が所有するリソースへのアクセスを许可する証明でもあり、クライアントがリソースサーバーのリソースへアクセスする际に必要になるものです。アクセストークンは认可における中核を担っており、翱础耻迟丑2.0の仕様を一言で要约すると、アクセストークンを発行する仕组み、とも言えます。

アクセストークンはセキュリティに直結します。リソース所有者が一度許可したからと言って、いつまでもリソースにアクセスできる状況は好ましくありません。なのでアクセストークンには有効期限が設けられています。有効期限は認可サーバーによって異なります。Keycloakではデフォルトでは5分ほどですし、Microsoft ID Platformでは60分から90分をランダムに割り振ります。

アクセストークンの有効期限が切れた际には再発行してもらう必要があります。再発行时に必要となるのがリフレッシュトークンです。通常、アクセストークンとリフレッシュトークンはセットで発行されます。

认可コードによる付与方式

繰り返しになりますが、翱础耻迟丑2.0は、认可サーバーからクライアントへ、アクセストークンを発行する仕组みです。あくまで仕组みであり、その手顺(认可付与方式)を定めたものになります。

OAuth2.0では、世の中の幅広いユースケースに対応するために、4つの認可付与方式を用意しています。今回はその1つでよく使われる「认可コードによる付与方式」を紹介します。

各要素でのやり取りは贬罢罢笔で行われます。また、通信経路の暗号化として罢尝厂を用いることが推奨されています。

まず初めに、リソース所有者は认可サーバーの认可エンドポイントにリダイレクトされます。リダイレクトされた先では、认可サーバーとリソース所有者间で、リソースへのアクセス権限をクライアントに付与しても良いか、确认が行われます。

确认が取れた场合、认可サーバーは「认可コード」を発行し、リソース所有者をクライアントへリダイレクトさせます。そのリダイレクトでリソース所有者は认可コードをクライアントへ渡します。认可コードを受け取ったクライアントは、その认可コードを使って认可サーバーからアクセストークンを取得します。

何故、わざわざ认可サーバーはリソース所有者へ、アクセストークンではなく认可コードを渡すのかというと、リソース所有者にアクセストークンを渡さないためです。もしリソース所有者が第3者の端末で操作していた场合、第3者の端末にアクセストークンが保存されてしまい、情报漏洩が起きてしまいます。

おわりに

翱础耻迟丑2.0は世の中の幅広いユースケースに対応するために、アクセストークンの受け渡し手顺に特化して仕様が定められています。そのため、アクセストークンの中身がどうなっているのか、アクセストークンの検証方法など、多くの仕様が翱础耻迟丑2.0で定められておらず、认可サーバーによって実装が异なります。その柔软さが多くの环境で翱础耻迟丑2.0が利用される要因でもあり、実际に翱础耻迟丑2.0を构筑する际のハードルになっていると感じます。

冒頭でも述べた通り、OAuth2.0では認証は想定していません。認証はOAuth2.0を拡張したOpen ID Connectで行います。次回はOpen ID Connectについてお話ししたいと思います。

ではまた。

The post 翱础耻迟丑2.0による権限の委譲 first appeared on 株式会社麻豆原创.

]]>