Question
· Feb 3, 2023

Autentication OAuth 2.0 Microsoft Office 365

Hi,

I use Caché COS and I'm having trouble doing a POP3 on the Microsoft email server using OAuth 2.0 authentication.

I'm using the following program to accomplish this task:

QGPOP ; Recebe e-mail da Microsoft Office 365
  Set server=##class(%Net.POP3).%New()
  Set server.port=995
  Set server.StoreAttachToFile=1
  Set server.AttachDir="D:\HOME\CNTIRET"
  Set servername="outlook.office365.com"
  Set user="importacao@ferrolene.com.br",pass="xxxxxx"
  Set AccessToken="exxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
  set server.SSLConfiguration="Transnovag"
  Set status=server.Connect(servername,user,pass,AccessToken)
  Do $System.Status.DisplayError(status)
  set status=server.GetMailBoxStatus(.NumMensagens,.TamTotalMensagens)
  w !!,"Nr. de mensagens na pasta: ",NumMensagens,!!
  Do $System.Status.DisplayError(status)
  s closeserver=server.%Close()
  Quit
  
I'm getting the following error message:

%SYS>ZR  D ^QGPOP
Erro #6015: Servidor POP3 reportou erro: -ERR Authentication failure: unknown user name or bad password..

Has anyone ever been able to make that connection?

Grateful.

Claudio Vieira

Product version: IRIS 2022.1
$ZV: IRIS for Windows (x86-64) 2022.1.1 (Build 374U) Tue Oct 18 2022 17:39:18 EDT
Discussion (4)3
Log in or sign up to continue

If you are using an access token, do not also send a password.

How are you getting the access token? Are you including the necessary scopes for email? You need to use scopes https://outlook.office.com/POP.AccessAsUser.All and https://outlook.office.com/SMTP.Send (or similar) to send and receive email.

Microsoft also requires a tenant id in the request, for example:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize
where "common" is the tenant id for an outlook.com email address, but you may need to use the tenant id for ferrolene.com.br

Thank you for returning Mr. Clark,
When I do not send the password is presented another error:

Sending: Set status=server.Connect(servername,user,pass,AccessToken)
Error returned: "Erro #6015: Servidor POP3 reportou erro: -ERR Authentication failure: unknown user name or bad password.."

Sending: Sending: Set status=server.Connect(servername,user,AccessToken)
Error returned: "Erro #6015: Servidor POP3 reportou erro: -ERR Protocol error. Connection is closed. 10."

The Token is being obtained through Postman.
I'm using the following Scopo: "offline_access openid User.Read POP.AccessAsUser.All SMTP.Send IMAP.AccessAsUser.All"

I'm sending the following keys in the Postman:

-client_id
-scope
-redirect_url
-grant_type
-client_secret
-code.

Grateful

Claudio Vieira

Set status=server.Connect(servername,user,AccessToken) needs to be
Set status=server.Connect(servername,user,,AccessToken)

To get the token I use:

url="https://login.microsoftonline.com/common/oauth2/v2.0/authorize?response_type=code&client_id={id}&redirect_uri={redirect}&scope=openid%20offline_access%20https%3A//outlook.office.com/POP.AccessAsUser.All%20https%3A//outlook.office.com/SMTP.Send&state={state}&nonce={nonce}&response_mode=form_post&access_type=offline&code_challenge={challenge}&code_challenge_method=S256&prompt=consent"

client_id=  
scope="openid offline_access https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send"
access_type="offline"
response_mode="form_post" 
response_type="code" 
code_challenge=
code_challenge_method="S256"
nonce=
prompt=consent"
state=

The client_secret is in the post form.
code_challenge/method, nonce, and state may be optional, but desirable for security.
prompt="consent" changes how the authorization is done and probably optional.
access_type="offline" is probably optional since you have the offline_access scope.

I found that adding some additional scopes would prevent the token from working for retrieving email.

Hi, 

I have the same problem.
I want to connect to office365 using OAuth2 and the IMAP protocol.

I was inspired by this post to use IMAP in IRIS : https://community.intersystems.com/post/implementing-imap-client-intersy...

I always have a system error when launching the command to connect in OAUT2

Do you know how to connect in OAUTH2 with IMAP in IRIS?

Here is the method : 

Method SendCommand(pCommand As %String = "") As %String

{

    Do ..Log("Dans BastideIMAPHelper :  SendCommand")

    Set currIO = $IO

    Set exception = ""

    Try {

        Set command = ""

        If (pCommand '= "") {

            Set tag = ..GetTag()

            Set command = tag_" "_pCommand

        }

        Do ..Log("Using device: "_..Device)

        Use ..Device

        If ($FIND(command, " AUTHENTICATE ") > 0) {

            // don't log passwords

         Set command = "AUTHENTICATE XOAUTH2 " _ authorizationHeader

            Do ..Log("Sending command 1: "_$P(command, " ", 1, 3)_" <password hidden>")

        }

     

        Write:(command '= "") command,!

       #; Set status = $zf(-1, command)

        Set ..CurrentCommand = pCommand

        Set ..CurrentTag = tag

        Do ..ReadResponse(.response)

    }

    Catch ex {

        Set exception = ex

        Do ..Log("Error in command execution: "_ex.DisplayString())

    }

    Use currIO

    Throw:$IsObject(exception) exception

    Return response

}

/// Description

Method ReadResponse(ByRef pResponse As %String) [ Internal ]

{

    Try {

    Set buffer = ""

    Set pResponse = ""

    Set tokensLine = ""

    While(1) {

        Read buffer:..Timeout

        Set readOK = $TEST

        Set pResponse = pResponse_buffer

        If (..CurrentCommand = "") Quit

        If (readOK) {

            // splits the current response by CRLF

            Set lines = $LISTFROMSTRING(buffer, $Char(13, 10))

            // if the whole response was retrieved, the line with the

            // tag of the command is the (n-1)-th, due the message

            // finishes with CRLF, so the n-th list element is ""

            Set ackLine = $LISTGET(lines, * - 1)

            // splits the lines by white space

            Set tokensLine = $LISTFROMSTRING(ackLine, " ")

            // if the whole message was retrieved, the first token has

            // the tag of the command

            Set tagToken = $LISTGET(tokensLine, 1)

            // check if the first token is the expeted tag, if so, the

            // whole message was retrieved and leave the loop

            If (tagToken = ..CurrentTag) Quit

        } Else {

            Quit

        }

    }

    }

    Catch ex {

        Set tSC=ex.AsStatus()

        Set exception = ex

        Do ..Log("Error in ReadResponse: "_ex.DisplayString())

    }

    // check if the whole message was retrieved and its status is OK

    Set ackToken = $LISTGET(tokensLine, 2)

    If (ackToken '= "OK") {

      Throw ##class(IMAPException).%New("IMAP error: "_$LISTTOSTRING(tokensLine, " "))

    }

}

Here is the command log 

command  : TAG1 AUTHENTICATE XOAUTH2 Bearer " AcccessToken value"

Here is error :

ERROR #5002: ObjectScript error: <WRITE>SendCommand+22

Thank you very much for your help