Accessing a Web Service that uses Microsoft Single Sign On for OAuth

Does anyone have a NetTalk example of this?

I created an example of this for a client. It’s a PITA but it is doable. I’ll see if I can find my example.

2 Likes

Hi Paul,

Just to be clear to the audience here, are you building a NT Webserver?

NetTalk can be many things.
Mark

I have connected more times to external services using OAuth with Nettalk, for the purpose of sync data. Nettalk OAuth class has to be used.

hth
Nenad

OAuthLogin PROCEDURE (*oAuthParametersGroup pParms)

Ans                  LONG                                  ! 
Info                 STRING(255)                           ! 
UserControlled       Long
Window               WINDOW('Login'),AT(,,434,290),FONT('Segoe UI',10,,FONT:regular),DOUBLE,AUTO,SYSTEM
                       BUTTON('Start'),AT(327,272,50,14),USE(?StartButton),HIDE
                       BUTTON('Close'),AT(382,272,50,14),USE(?Close)
                     END

    omit('***',WE::CantCloseNowSetHereDone=1)  !Getting Nested omit compile error, then uncheck the "Check for duplicate CantCloseNowSetHere variable declaration" in the WinEvent local template
WE::CantCloseNowSetHereDone equate(1)
WE::CantCloseNowSetHere     long
    !***
ThisWindow           CLASS(WindowManager)
Init                   PROCEDURE(),BYTE,PROC,DERIVED
Kill                   PROCEDURE(),BYTE,PROC,DERIVED
TakeAccepted           PROCEDURE(),BYTE,PROC,DERIVED
TakeEvent              PROCEDURE(),BYTE,PROC,DERIVED
TakeWindowEvent        PROCEDURE(),BYTE,PROC,DERIVED
                     END

Toolbar              ToolbarClass
!Local Data Classes
oAuth                CLASS(NetOAuth)                       ! Generated by NetTalk Extension (Class Definition)
Done                   PROCEDURE(),DERIVED
ErrorTrap              PROCEDURE(string errorStr,string functionName),DERIVED
UserLogin              PROCEDURE(STRING pUrl),DERIVED

                     END


  CODE
  GlobalResponse = ThisWindow.Run()                        ! Opens the window and starts an Accept Loop
  RETURN(Ans)

!---------------------------------------------------------------------------
DefineListboxStyle ROUTINE
!|
!| This routine create all the styles to be shared in this window
!| It`s called after the window open
!|
!---------------------------------------------------------------------------

ThisWindow.Init PROCEDURE

ReturnValue          BYTE,AUTO

  CODE
  GlobalErrors.SetProcedureName('OAuthLogin')
  SELF.Request = GlobalRequest                             ! Store the incoming request
  ReturnValue = PARENT.Init()
  IF ReturnValue THEN RETURN ReturnValue.
  SELF.FirstField = ?StartButton
  SELF.VCRRequest &= VCRRequest
  SELF.Errors &= GlobalErrors                              ! Set this windows ErrorManager to the global ErrorManager
  CLEAR(GlobalRequest)                                     ! Clear GlobalRequest after storing locally
  CLEAR(GlobalResponse)
  SELF.AddItem(Toolbar)
  IF SELF.Request = SelectRecord
     SELF.AddItem(?Close,RequestCancelled)                 ! Add the close control to the window manger
  ELSE
     SELF.AddItem(?Close,RequestCompleted)                 ! Add the close control to the window manger
  END
  SELF.Open(Window)                                        ! Open window
                                               ! Generated by NetTalk Extension (Start)
  oAuth.SuppressErrorMsg = 1         ! No Object Generated Error Messages ! Generated by NetTalk Extension
  oAuth.init()                     ! Generated by NetTalk Extension
  if oAuth.error <> 0
    ! Put code in here to handle if the object does not initialise properly
  end
  Do DefineListboxStyle
  Alert(AltKeyPressed)  ! WinEvent : These keys cause a program to crash on Windows 7 and Windows 10.
  Alert(F10Key)         !
  Alert(CtrlF10)        !
  Alert(ShiftF10)       !
  Alert(CtrlShiftF10)   !
  Alert(AltSpace)       !
  WinAlertMouseZoom()
  WinAlert(WE::WM_QueryEndSession,,Return1+PostUser)
  INIMgr.Fetch('OAuthLogin',Window)                        ! Restore window settings from non-volatile store
  SELF.SetAlerts()
  If oAuth.init(pParms) = NET:OK
    ans = net:Ok
    Return Level:Notify
  End
  
  ans = net:NotOk  ! set ans to login not successful as default value
  
  info = 'Connecting to ' & clip(pParms.pServiceName) & '. This may take several seconds. Please be patient.'
  UserControlled = false
  
  Post(EVENT:Accepted,?StartButton)
  RETURN ReturnValue


ThisWindow.Kill PROCEDURE

ReturnValue          BYTE,AUTO

  CODE
  oAuth.Kill()                              ! Generated by NetTalk Extension
  If self.opened Then WinAlert().
  ReturnValue = PARENT.Kill()
  IF ReturnValue THEN RETURN ReturnValue.
  IF SELF.Opened
    INIMgr.Update('OAuthLogin',Window)                     ! Save window data to non-volatile store
  END
  GlobalErrors.SetProcedureName
  RETURN ReturnValue


ThisWindow.TakeAccepted PROCEDURE

ReturnValue          BYTE,AUTO

Looped BYTE
  CODE
  LOOP                                                     ! This method receive all EVENT:Accepted's
    IF Looped
      RETURN Level:Notify
    ELSE
      Looped = 1
    END
    CASE ACCEPTED()
    OF ?StartButton
      oAuth.startAuth()
    END
  ReturnValue = PARENT.TakeAccepted()
    RETURN ReturnValue
  END
  ReturnValue = Level:Fatal
  RETURN ReturnValue


ThisWindow.TakeEvent PROCEDURE

ReturnValue          BYTE,AUTO

Looped BYTE
  CODE
  LOOP                                                     ! This method receives all events
    IF Looped
      RETURN Level:Notify
    ELSE
      Looped = 1
    END
    oAuth.TakeEvent()                 ! Generated by NetTalk Extension
  ReturnValue = PARENT.TakeEvent()
  If event() = event:VisibleOnDesktop !or event() = event:moved
    ds_VisibleOnDesktop()
  end
    RETURN ReturnValue
  END
  ReturnValue = Level:Fatal
  RETURN ReturnValue


ThisWindow.TakeWindowEvent PROCEDURE

ReturnValue          BYTE,AUTO

Looped BYTE
  CODE
  LOOP                                                     ! This method receives all window specific events
    IF Looped
      RETURN Level:Notify
    ELSE
      Looped = 1
    END
    CASE EVENT()
    OF EVENT:CloseDown
      if WE::CantCloseNow
        WE::MustClose = 1
        cycle
      else
        self.CancelAction = cancel:cancel
        self.response = requestcancelled
      end
    END
  ReturnValue = PARENT.TakeWindowEvent()
    CASE EVENT()
    OF EVENT:OpenWindow
        post(event:visibleondesktop)
    END
    RETURN ReturnValue
  END
  ReturnValue = Level:Fatal
  RETURN ReturnValue


oAuth.Done PROCEDURE


  CODE
  PARENT.Done
  pParms = self.parms
  info = 'Login to ' & clip(pParms.pServiceName) & ' Successful'
  
  display()
  if UserControlled
    Message(info,pParms.pServiceName)
  end
  ans = net:Ok ! success
  post(event:closewindow)


oAuth.ErrorTrap PROCEDURE(string errorStr,string functionName)


  CODE
  PARENT.ErrorTrap(errorStr,functionName)
   Clear(ERR:Record)
   ERR:Description = 'Oath error. ' & errorStr
   ERR:Date = Today()
   ERR:Time = Clock()
   ERR:Proc = 'Integrator'
   ERR:Location = 'Error'
   Access:ErrorLog.TryInsert()
   post(event:closewindow)


oAuth.UserLogin PROCEDURE(STRING pUrl)


  CODE
  UserControlled = true
  !ThisViewer1.Load (pUrl)
  PARENT.UserLogin(pUrl)

when you call it you use netwebclient

net                  CLASS(NetWebClient)                   ! Generated by NetTalk Extension (Class Definition)
ErrorTrap              PROCEDURE(string errorStr,string functionName),DERIVED
PageReceived           PROCEDURE(),DERIVED
Send                   PROCEDURE(),DERIVED

                     END

and this is example of requesting some data using some url (querystring)

SendQuery            ROUTINE

   IF LoginFlag <> 'Y' THEN
      Do SetLogin
   END

   !debug
   !sth.SetValue(Clip(OAuthParms.rToken))
   !sth.SaveFile('log.txt')
   !message('check token')

   net.Authorization = 'Bearer ' & Clip(OAuthParms.rToken)
   net.get(Clip(QueryString))

SetLogin             ROUTINE
   clear(OAuthParms)
   OAuthParms.pServiceName = 'AutoData'
   OAuthParms.pOAuthVersion = 2
   !OAuthParms.pClientId = 'xxxxx'
   !OAuthParms.pClientSecret = 'xxxx'
   OAuthParms.pClientId = Clip(PNT:NavBinName) 
   OAuthParms.pClientSecret = Clip(PNT:NavItemName) 
   OAuthParms.pGrantType = 'client_credentials'
   OAuthParms.pScope = '' !'scope1'
   OAuthParms.pForce = TRUE
   OAuthParms.pRefreshTokenURL = ''
   OAuthParms.pAccessTokenURL = Clip(PNT:SetOwner) & '/oauth2/token' !'https://someservice.com/oauth2/token'
   !ReturnValue# = OAuthLogin(OAuthParms) ! this is the OAuthLogin proc in your app created earlier.
   if OAuthLogin(OAuthParms) = net:ok ! this is the OAuthLogin proc in your app created earlier.
      LoginFlag = 'Y'
      LoginTime = Clock()
   end


1 Like

Easy Edge (Chromium) has the AllowSingleSignOnUsingOSPrimaryAccount option, when true it allows to automatically sign the user into websites that use Microsoft login mechanisms (AAD/Entra ID or MSA), leveraging the account with which the user is signed into Windows. This allows for a seamless authentication experience within the application, avoiding repetitive login prompts.

1 Like

Not in this instance. That’s next for a different project.

We have a 3rd party product that uses MS SSO to authenticate.

I need to use Nettalk to access their API.

So I need to get the access token from MS.

Using the NetDrive/OneDrive and NetPAuth examples I believe I am now getting the right token (I authenticate with MS) but the terminology seems to be inconsistent and complexity of options in the Enterprise apps high..

I think NetTalk uses Google terminology for OauthParams and MS is slightly different.

So just looking for clarity from someone who might have done this before.

Thank you. There is a lot of clarifying details in there.

Very helpful !