<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  </head>
  <body>
    I would like to authenticate users that use the PLAIN mechanism
    against an oauth2 idp (in this case it's an Azure AD B2C).<br>
    I configured dovecot.conf with<br>
    <br>
    <font face="monospace">auth_mechanisms = plain oauthbearer xoauth2<br>
      passdb {<br>
        driver = oauth2<br>
        mechanisms = plain login<br>
        args = /etc/dovecot/dovecot-oauth2.plain.conf.ext<br>
      }</font><br>
    <br>
    and in /etc/dovecot/dovecot-oauth2.plain.conf.ext I have<br>
    <br>
    <font face="monospace">grant_url =
<a class="moz-txt-link-freetext" href="https://simons0f7b2c.b2clogin.com/simons0f7b2c.onmicrosoft.com/B2C_1_ROPC_Auth/oauth2/v2.0/token?scope=xxxxx-5be3-405a-babb-xxxx">https://simons0f7b2c.b2clogin.com/simons0f7b2c.onmicrosoft.com/B2C_1_ROPC_Auth/oauth2/v2.0/token?scope=xxxxx-5be3-405a-babb-xxxx</a><br>
      client_id = xxxxx-5be3-405a-babb-xxxx<br>
      client_secret = m6xxxxxxxx<br>
      username_attribute = extension_PreferredLoginUsername<br>
      #introspection_url = <a class="moz-txt-link-freetext" href="http://localhost:8000/introspect">http://localhost:8000/introspect</a><br>
      #introspection_mode = post<br>
      use_grant_password = yes<br>
      debug = yes<br>
      pass_attrs = host=127.0.0.1 proxy=y proxy_mech=xoauth2
      pass=%{oauth2:access_token}</font><br>
    <br>
    I can see that dovecot sends a request to simons0f7b2c.b2clogin.com
    that looks like this:<br>
    <br>
    <font face="monospace">POST
/simons0f7b2c.onmicrosoft.com/B2C_1_ROPC_Auth/oauth2/v2.0/token?scope=xxxxx-5be3-405a-babb-xxxx
      HTTP/1.1<br>
      Host: simons0f7b2c.onmicrosoft.com<br>
      Date: Tue, 04 Oct 2022 15:43:42 GMT<br>
      User-Agent: dovecot-oauth2-passdb/2.3.16<br>
      Content-Length: 169<br>
      Connection: Keep-Alive<br>
      Content-Type: application/x-www-form-urlencoded<br>
      <br>
<a class="moz-txt-link-abbreviated" href="mailto:grant_type=password&username=sp12@31337.it&password=">grant_type=password&username=sp12@31337.it&password=</a><userpass>&client_id=xxxxx-5be3-405a-babb-xxxx&client_secret=m6xxxxxxxx<br>
    </font><br>
    and the response is something like<br>
    <font face="monospace"><br>
      HTTP/1.1 200 OK<br>
      Cache-Control: no-store, must-revalidate, no-cache<br>
      Content-Type: application/json; charset=utf-8<br>
      Set-Cookie: x-ms-cpim-trans=; domain=simons0f7b2c.b2clogin.com;
      expires=Thu, 04-Oct-2012 15:29:04 GMT; path=/; SameSite=None;
      secure; HttpOnly<br>
      x-ms-gateway-requestid: 6ce588cf-9e35-491e-8393-18da8ccbe2cd<br>
      X-Frame-Options: DENY<br>
      Public: OPTIONS,TRACE,GET,HEAD,POST<br>
      Strict-Transport-Security: max-age=31536000; includeSubDomains<br>
      X-Content-Type-Options: nosniff<br>
      X-XSS-Protection: 1; mode=block<br>
      Allow: OPTIONS<br>
      Allow: TRACE<br>
      Allow: GET<br>
      Allow: HEAD<br>
      Allow: POST<br>
      Date: Tue, 04 Oct 2022 15:29:03 GMT<br>
      Content-Length: 1003<br>
      <br>
{"access_token":"eyJ0xxxxx9uIw","token_type":"Bearer","expires_in":"3600"}<br>
    </font><br>
    <br>
    Decoding the access_token I can see that there is a field
    extension_PreferredLoginUsername:<br>
    <br>
    <font face="monospace">{<br>
        "typ": "JWT",<br>
        "alg": "RS256",<br>
        "kid": "X5eXk4"<br>
      }.{<br>
        "iss": <a class="moz-txt-link-rfc2396E" href="https://simons0f7b2c.b2clogin.com/xxxxx/v2.0/">"https://simons0f7b2c.b2clogin.com/xxxxx/v2.0/"</a>,<br>
        "exp": 1664898983,<br>
        "nbf": 1664895383,<br>
        "aud": "xxxxx-5be3-405a-babb-xxxx",<br>
        "idp": "LocalAccount",<br>
        "sub": "969xxx7",<br>
        "extension_PreferredLoginUsername": "s2",<br>
        "tfp": "B2C_1_ROPC_Auth",<br>
        "azp": "89xxxc0",<br>
        "ver": "1.0",<br>
        "iat": 1664895383<br>
      }</font><br>
    <br>
    so the field extension_PreferredLoginUsername is there, but dovecot
    says:<br>
    <br>
    <font face="monospace">dovecot: auth: Debug: http-client: conn
      40.126.31.64:443 [1]: Got 200 response for request [Req1: POST
<a class="moz-txt-link-freetext" href="https://simons0f7b2c.b2clogin.com/simons0f7b2c.onmicrosoft.com/B2C_1_ROPC_Auth/oauth2/v2.0/token?scope=xxxxx-5be3-405a-babb-xxxx">https://simons0f7b2c.b2clogin.com/simons0f7b2c.onmicrosoft.com/B2C_1_ROPC_Auth/oauth2/v2.0/token?scope=xxxxx-5be3-405a-babb-xxxx</a>]:
      OK (took 1016 ms + 327 ms in queue)<br>
      dovecot: auth: Debug:
      oauth2(<a class="moz-txt-link-abbreviated" href="mailto:sp12@31337.it,192.168.0.4">sp12@31337.it,192.168.0.4</a>,<p0vv9jbq3MrAqAAE>):
      Password grant succeeded<br>
      dovecot: auth: Debug:
      oauth2(<a class="moz-txt-link-abbreviated" href="mailto:sp12@31337.it,192.168.0.4">sp12@31337.it,192.168.0.4</a>,<p0vv9jbq3MrAqAAE>):
      Processing field access_token<br>
      dovecot: auth: Debug:
      oauth2(<a class="moz-txt-link-abbreviated" href="mailto:sp12@31337.it,192.168.0.4">sp12@31337.it,192.168.0.4</a>,<p0vv9jbq3MrAqAAE>):
      Processing field token_type<br>
      dovecot: auth: Debug:
      oauth2(<a class="moz-txt-link-abbreviated" href="mailto:sp12@31337.it,192.168.0.4">sp12@31337.it,192.168.0.4</a>,<p0vv9jbq3MrAqAAE>):
      Processing field expires_in<br>
      dovecot: auth: Error:
      oauth2(<a class="moz-txt-link-abbreviated" href="mailto:sp12@31337.it,192.168.0.4">sp12@31337.it,192.168.0.4</a>,<p0vv9jbq3MrAqAAE>): oauth2
      failed: Password grant failed: No username returned<br>
      dovecot: auth: Debug:
      oauth2(<a class="moz-txt-link-abbreviated" href="mailto:sp12@31337.it,192.168.0.4">sp12@31337.it,192.168.0.4</a>,<p0vv9jbq3MrAqAAE>):
      Finished passdb lookup<br>
      dovecot: auth: Debug:
      pam(<a class="moz-txt-link-abbreviated" href="mailto:sp12@31337.it,192.168.0.4">sp12@31337.it,192.168.0.4</a>,<p0vv9jbq3MrAqAAE>):
      Performing passdb lookup</font><br>
    <br>
    <br>
    So, why does dovecot say "No username returned"? The username is
    there! Do I have to configure something else?<span class="jwtHeader"></span><span
      class="jwtClaims"></span>
  </body>
</html>