NetTalk OAuth
Available
in NetTalk Desktop, NetTalk Server and NetTalk Apps. Applies to Desktop
and Server (ABC or Clarion) apps.
Introduction
OAuth is a common approach for logging onto a Web
Service or Web application.
The method is popular because it allows your program to log into the
service, without your program actually discovering the user name or
password. Once you are logged in you can then make use of resources which
that API provides. In this document this will be referred to as First
Party Authentication. You are authenticating with a service in order to
use that service.
Using a service is a separate topic to OAuth. In this document the goal is
to log into the service, and receive a Token. The Token is then used later
on by other NetTalk classes (or indeed your own classes) to interact with
the service.
OAuth also allows the service to authenticate using a 3rd party - not the
web service itself. For example you might log into a web service providing
the weather, but do so using a Google Login. The weather service does not
get your Google credentials, but it trusts Google that you are who you say
you are. In this document this will be referred to as Third Party
Authentication.
There are two popular version, OAuth 1a and OAuth 2. Both are supported.
Your app could allow the client to select among different OAuth providers
- they are not bound to the one provider that you specify.
The OAuth provider usually provides a web interface for the user to login.
In order for this to work in a Clarion Desktop application you will need
an HTML control to interact with the provider. This HTML control can
(usually) be inside your program, using Chrome Explorer, or it can be
outside your program. (Tip: Google services require that
the control be outside your program.)
The OAuth provider provides your program with a Token (which is just a
string). This string is stored so that the user does not need to log in
(to the web service) again. Even if the user changes their password at the
provider, the token is still valid.
Requirements
OAuth requires the user to interact with the provider
in a web page. For this reason
ChromeExplorer is recommended
[1][2].
In most cases Interaction with the service takes place using the JSON
format so for this reason
jFiles is required.
[1] Note: ChromeExplorer uses
the Chromium engine which is up to date, whereas
FileExplorer uses the IE OCX control which is
obsolete and is no longer supported by some services. If you are using
File Explorer you will need to upgrade to ChromeExplorer at some point.
NetTalk currently ships with examples for both ChromeExplorer and File
Explorer, and also examples for using an external browser.
[2] Note: Technically, the
user does not need to log in inside your program. They can log in outside
the program, using a modern browser. While less elegant this approach is
also
required by some services (like Google). For more
on this see
Using an External Browser to Login.
Background
OAuth is a way for your Webclient class (or class
derived from Webclient) to authenticate with a remote server. The whole
point of an OAuth login is to get a token (which is just a string) and
then this token is used when communicating with that server.
Your program will need an OAuthLogin procedure in order for the user to
log in to the service. Unlike other protocols your program does not ask
for (or store) the user's login and password. Rather you just provide the
window for them to login on, and that window provides your app with the
token.
The token can be stored, so the login window will first attempt to use a
stored token. If no stored token exists then the Login window will be
displayed to the user so they can log in, a token can be received, and
stored.
Your webclient procedure will then use this token in the Authorization
property. That is ultimately what this whole document is about, simply
getting the token so it can be used in the Authorization property.
Under the hood there are actually two flavors of OAuth in the wild. OAuth
1a is an earlier specification, and used by services like Flickr,
Xero and Twitter. OAuth2 is a later specification and used by services
such as Dropbox, Google, Microsoft, Yahoo and so on. Some services provide
both options - where you do have an option rather use the OAuth 2 version.
Using NetOAuth you should be able to log into any API which requires an
OAuth connection. Some examples (and detailed instructions) for popular
services appear below, but the principle for them is all the same. If you
are attempting to connect to a service not documented below, and you are
unfamiliar with the process then we recommend you walk through this
process with 2 or 3 providers to get a feel for it. It is likely that with
this experience you will be able to figure out what is needed for any API.
In this section it is assumed that your client will be connecting to the
service using their credentials, not your credentials. They will be
logging into the service using NetOAuth using their own login and
password.
That said it is also necessary for the developer to have their own account
on the service (in almost all cases a free account.) This is different to
other protocols (like say email) where a user can send to an ISP email
server even though the developer has never used that server.
While the developer will need their own login to the service (to
"register" the application) the end user will not need the developer's
credentials, and will not have access to the developer's account.
The basic pattern for all the services is the same;
- Create an account at the service
- Register the app on the service
- Gather (or set) the vital settings the program will need.
- Use those settings in a Window, passing them to the NetOAuth object.
Vital Settings
In order for your app to log in to a service you
will need to know the following information. Your program will need to
either hard-code, or load (as a setting) this information.
Property |
Description |
OAuth Version |
the version of the OAuth API that the service supports.
Possible values are 1 or 2. Some services support both, in which
case use Version 2. |
Client ID |
This is something that identifies your application to the
service. It's typically a string of random characters. It is
also sometimes called the App Key, the Application ID, the
Consumer Key or something like that. |
Client Secret |
This is a "password" that belongs to your application. It is
typically a string of random characters. It's also sometimes
called App Secret, Consumer Secret, Password and so on. |
Redirect URL |
This is the URL the service will redirect the browser to on a
successful login. The window in your application will intercept
this URL. Sometimes this URL is not set by you, but is set (to http://localhost) by the service
as a default value.
For Desktop - if given the option you can enter anything you
like, but the simplest, and most compatible option seems to be http://localhost or just
localhost. (Some services want the HTTP part, others explicitly
don't want it.)
For Web - you will enter the complete URL for your oAuthLoginWeb
form (https://yourdomain/oAuthLoginWeb) here. Note that you will
also need to register this URL with the service as an allowed
Redirect URL for your service. |
Scope |
This item is optional, and depends on the service. Usually
used by services that offer different levels of API, or
different API's. If it's not immediately obvious then you can
set it to a blank string in the program. |
Request Token URL |
Only required by services that use OAuth version 1. This URL
is usually listed in the Service Documentation for that service. |
Authorize URL |
A URL the program will use to request a token from the
service. This URL is usually listed in the Service Documentation
for that service. |
Access Token URL |
A second URL used by the service during the OAuth login
process. This may also be called the Exchange URL. This URL is
usually listed in the Service Documentation for that service. |
NetDrive
You may be here because you are implementing
NetDrive or some other class that needs OAuth
support in your program.
NetDrive and OAuth are different topics because NetDrive is just one
example of a service that uses OAuth logins. If you are using NetDrive
then you need to also implement the OAuth Client, simply because NetDrive
will need to use that. For the purposes of OAuth it does not matter what
the OAuth login is needed for - the process for implementing it is the
same.
So if you are using OAuth with NetDrive, or if you are using it for a
simple WebClient class, go ahead and follow the instructions below.
Implementing OAuth (for Desktop Apps)
NetTalk OAuth requires a number of other CapeSoft
Accessories in order to work. So the first step is to make sure that the
global extensions for NetTalk, StringTheory, Chrome Explorer (or File
Explorer or neither) and jFiles are added to the application.
When you write a program that makes use of an OAuth service, you will need
to register your application with that service first. This is necessary to
get the
vital settings your app will need.
Examples of registering with various services can be found
below.
If your service is not on this list then it is recommended that you walk
through the process for 2 or 3 services that have the same OAuth version
support. Once you have followed the process a couple times you will be
ready to tackle the settings for a new service.
OAuthLogin Procedure
The OAuthDemo example can be found in the
\clarion\examples\nettalk\oauth folder. There are sub folders
there for ABC and Legacy. These examples contain an example
OAuthLogin
procedure. The main window demonstrates calling this procedure
for many different services. You will need to import this
OAuthLogin
procedure directly into your application.
[1]
Visually the window contains only a few controls, but you are welcome to
adjust the window visually to suit the look of your application.
The
OAuthLogin procedure takes a single
Group parameter, called
pParms. This
contains both the settings the procedure will need (based on the service
you are connecting to) and will also contain the results of the login as
well once the login is completed. Pretty much all you have to do to
implement OAuth for any service is declare and populate this parameter
correctly.
Calling the OAuthLogin Procedure
If you are using a class (like say
NetDrive) which is designed to be used with
NetOAuth then see the documentation for that class, and also the section
below on
Using Classes that Support NetOAuth.
If you are not using a class that is designed for NetOAuth, but a class
designed for OAuth in general then you have slightly more work to do.
First you need to declare a variable of the correct type.
OAuthParms
Like(OAuthParametersGroup)
Next you will populate the group
clear(OAuthParms)
OAuthParms.pServiceName = 'Google'
OAuthParms.pForce = true
OAuthParms.pExternalBrowser = netOAuth:UseLocalBrowser
OAuthParms.pOAuthVersion = 2
OAuthParms.pClientId = '***something***'
OAuthParms.pClientSecret = '***something***'
OAuthParms.pRedirectURL = 'http://localhost'
OAuthParms.pScope = 'https://www.googleapis.com/auth/drive'
OAuthParms.pAuthorizeURL = 'https://accounts.google.com/o/oauth2/auth'
OAuthParms.pAccessTokenURL = 'https://accounts.google.com/o/oauth2/token'
Finally you will call the OAuthLogin procedure that you imported into
your application earlier.
The OAuthLogin procedure returns a LONG value, either
net:Ok
(for success) or something else for failure. Some parameters in the
OAuthParms group are updated by a successful login. (See
OAuthParametersGroup
for more information on that.)
Example of calling the OAuthLogin procedure
if OAuthLogin(OAuthParms) = net:Ok
! login successful
else
! login failed
end
Your code, or class can then access the contents of
OAuthParms
are required. The most likely value needed by the code is
OAuthParms.rToken, which is also known as the
AccessToken.
Example
The OAuthDemo apps have a
Main
procedure containing example settings for ten different services.
While these settings are valid, you will need to get your own settings
for your application. Using the example
ClientID and
ClientSecret values in your own application
is not permitted.
The
ClientID and
ClientSecret
fields in the OAuthDemo example are valid fields, which mean
the examples work, but you must not use these in your own program. Abuse
of these fields would lead to the Demo apps being deactivated which
would make them less useful to everyone in the long run.
The various
vital settings in the login
procedure are simply coded into the procedure as fixed strings. In your
application you may choose to elaborate on this, perhaps storing these
as settings in your program or fields in your database. You are of
course free to edit the procedure in this way.
The OAuthLogin procedure will return the values your program will need
to use later on in the
Parms parameter.
The program procedure should store these values so your user does not
have to login every time you use the API.
[2] The
OAuthLogin procedure will store these values in a simple INI file for
you. If the OAuthLogin procedure is called (and
parms.pForce
= false) then these stored values will be loaded and returned
to the caller for immediate use. The user will not need to login in this
case.
You can alter the code in OAuthLogin if you wish to store the values in
an alternate place.
It's worth reiterating here that your program does not "see" or "record"
the user's login or password. The whole point of OAuth is that the user
is able to login without exposing this to your program. All the program
sees are the Tokens returned by the remote service.
Notes
1. If you are building a
multi-dll system then you can import this procedure into any DLL in your
system as long as the procedure can be called by your WebClient (or
NetDrive) procedures. Set the procedure to Export so it can be used by
procedures in other DLL's as well.
2. This is service dependent. Some services place a
lifespan on the token returned. In some cases the token can be renewed,
in other cases it can't. For example the Xero service allows for a 30
minute window of API usage, after that the token expires and the user
will need to log in again.
PKCE Flow
One variation that some services prefer is PKCE
(pronounced Pixie) flow, compared to the Standard flow described
above.In Standard flow a Client Secret is passed as one of the
parameters in the parameters group passed to the OAuthLogin procedure.
In PKCE flow there is no client secret, and so that field is left blank.
In it's place the pCodeChallengeMethod field is set to one of S256
or plain.
clear(OAuthParms)
OAuthParms.pServiceName = 'Xero'
OAuthParms.pOAuthVersion = 2
OAuthParms.pClientId =
'9135C0FCC8F147F9BD74D050CA494CD6'
OAuthParms.pScope
=
'payroll.payslip'
! https://developer.xero.com/documentation/oauth2/scopes
OAuthParms.pCodeChallengeMethod = 'S256'
OAuthParms.pRedirectURL = 'http://localhost'
OAuthParms.pRequestTokenURL =
'https://identity.xero.com/connect/token'
OAuthParms.pAuthorizeURL =
'https://login.xero.com/identity/connect/authorize'
OAuthParms.pAccessTokenURL =
'https://identity.xero.com/connect/token'
Client Credentials and
Password Grant Types
Note: This section is here because some services
implement OAuth, but bypass the user-logging in requirement. This
section can be skipped for normal OAuth use.
The typical OAuth 2 process looks like this;
This is known as the
Authorization Code Grant Type.
As you can see this is a 2 step process. The
UserLogin
method is called, which then passes control to an end user
(typically in a Browser control) which allows the user to log in. The
goal of this is to get an authorization code value back from the service
(hence the name.)
In the second step the code is passed to the service as part of a
GetAccessToken request. This returns the token
to the program. The token will then allow access to all the other
methods in the API.
In some cases however the service reduces this requirement to a single
step. They bypass step 1, instead providing you with a single URL needed
to get a token. There are two forms of this.
The first is known as the
Client Credentials Grant
Type. In this situation the
client_id and
client_secret are essentially a login and
password.
The second is the
Password grant type where
a username and password field are sent (as well as optionally some other
fields.)
Implementing Client
Credentials Grant Type
Implementing this grant type is very similar to
the above instructions. The only difference is that the calling
procedure should set
OAuthParms.pGrantType = 'client_credentials'
The service provider will provide you with the necessary credentials -
typically something to put into the
client_id,
and
client_secret fields.
Here's a sample complete request;
clear(OAuthParms)
OAuthParms.pServiceName = 'AutoData'
OAuthParms.pOAuthVersion = 2
OAuthParms.pClientId = '***something***'
OAuthParms.pClientSecret = '***something***'
OAuthParms.pGrantType = 'client_credentials'
OAuthParms.pScope = 'scope1'
OAuthParms.pAccessTokenURL = 'https://account.autodata-group.com/oauth/access_token'
Implementing Password
Grant Type
The Password grant type is very similar to the
Client Credentials grant type, but uses a slightly different set of
fields. The user name and password are passed in their own fields, and
optionally other fields, like ClientId and Client secret can be used
for other things. For example;
clear(OAuthParms)
OAuthParms.pServiceName = 'AutoData'
OAuthParms.pOAuthVersion = 2
OAuthParms.pUserName = '***something***'
OAuthParms.pPassword = '***something***'
OAuthParms.pClientId = '***maybe something***'
OAuthParms.pClientSecret = '***maybe something***'
OAuthParms.pGrantType = 'password'
OAuthParms.pScope = 'scope1'
OAuthParms.pAccessTokenURL = 'https://account.autodata-group.com/oauth/access_token'
Implementing OAuth (for Web Server
Apps)
In some cases you will have a Web Server app which
will act as a Client to external services.
For example a user of your Web App may generate a report, and then wish to
upload that report to their OneDrive account.
Generally speaking the process for your Web Server app to login to
OneDrive is very similar to a Desktop program logging in to OneDrive. The
concepts are all the same. The primary difference is that there is no File
Explorer control in play, and the Redirect URL does not go to LocalHost
but goes back to the oAuthLoginWeb procedure in your web application.
The key differences between the Desktop app and the Server app are as
follows;
- There's no need to have File Explorer in the Web Server app.
- You will use a procedure called oAuthLoginWeb
to login, rather than oAuthLogin. oAuthLoginWeb is a
NetWebForm, which in turn will make use of a second procedure
oAuthLoginWork. Both of these procedures can be imported from
the example \examples\nettalk\web
server\oAuthClient (83).
- When registering your program with the service you will need to
register your actual oAuthLoginWork web page, and not LocalHost. In
other words the service (Dropbox et al) will send the user's browser
"back" to your Redirect URL when they have entered their details.
There's no server running on their machine, so LocalHost makes no
sense in this case. In pretty much all cases your server will
need this page to be an HTTPS page.
- In a desktop app the tokens are stored in a simple INI file. In a
web application multiple people may be using the application at the
same time so you will want to store the tokens in your database,
attached to each user, and move the values into Session Variables when
the user logs into your program (ie in your normal login process.)
Note the oauth.Load and
oauth.Save methods in the oAuthLoginWork
procedure where you can customize the loading and saving of
tokens.
oAuthLoginWeb Procedure
This procedure contains a button for the service you
are logging into. In the example the button for DropBox has been added.
the key things to note about this button are;
- On the Button tab, the Type is set to OAuth Login
- On the OnClick tab a number of fields are set that are specific to
the service you are connecting to. You can read more about
these settings in the Vital Settings
section.
Load and Save Tokens
Tokens (and other information) can (and should) be
saved between program runs. This means the user only has to login once,
the token is then good for some period of time (depending on the service.)
By default the
NetOAuth class saves the
token information in an INI file called
oAuth.Ini,
in the "current directory". This implies the following;
- The current directory is set to something useful. This is usually
the case, but if your program does not set, and maintain the current
directory (especially after calls to FILEDIALOG) then this not work
correctly.
- If the Current Directory is shared between users (as in say a
network data folder) then once one user logs in all users will have
access to the service.
- You are happy to use an INI file to store settings.
If any of the above conditions are not acceptable to your program, then
it is easy for you to override the location, and form, of the save. You
could save the INI file in a different location, or save the settings in
a database table, or whatever you prefer.
There are two methods provided, one called Load,
the other called Save. You can add your own
code to these methods in the OAuthLogin procedure,
BEFORE the parent call. If you do a RETURN statement
before the parent call then the parent call is suppressed (and so the
default INI code will not run.)
For details on the fields that need saving and loading see netOauth.Clw,
in the Load and Save
methods.
Using Tokens
The goal of the OAuth login is to get a Token. This is
a random string value which you can use in subsequent interactions with
the API as a form of authentication.
The exact way the server uses the token may vary from one service to
another. The most common approach though is that the token is passed as
part of the header in the Authorization field as a Bearer value. For
example;
net.Authorization = 'Bearer ' & OAuthParms.rToken
Using Classes that Support NetOAuth
If a class is designed using the
Guidelines
to Class Authors below then the use of that class (from an OAuth
point of view) will be very straight forward (at least from the OAuth
point of view.)
- Populate the derived UserLogin method.
The goal here is prime the supplied OAuthParms property,
and call the OAuthLogin procedure that
is in your application. For example;
parent.UserLogin(pForce)
self.OAuthParms.pClientId = '***some client id***'
self.OAuthParms.pClientSecret = '***some secret***'
ReturnValue = OAuthLogin(self.OAuthParms)
if ReturnValue = net:Ok
enable(?LOC:CurrentDir:Prompt,?PROGRESS1)
else
disable(?LOC:CurrentDir:Prompt,?PROGRESS1)
end
Return ReturnValue
Guidelines to Class Authors
Adding OAuth support to a class is very
straight-forward, and if done in a consistent way then users will find
using these classes easier. If you are an author of classes then this
section is for you.
The following features in your class are recommended;
- At the top of the include file include the NetOAuth.Inc
file
include('NetOAuth.Inc'),Once
- A Property in the app called OAuthParms (or similar) of type
Group(OAuthParametersGroup).
OAuthParms Group(OAuthParametersGroup).
- A method called UserLogin.
UserLogin PROCEDURE(Long pForce=false) Long,Proc,Virtual
In this method populate as many of the OAuthParms fields as is
practical for your class. For example the NetDriveDropBox
class is able to populate all the following fields, as these
are static for DropBox;
self.OAuthParms.pServiceName = 'Dropbox'
self.OAuthParms.pForce = pForce
self.OAuthParms.pOAuthVersion = 2
self.OAuthParms.pRedirectURL = 'http://localhost'
self.OAuthParms.pAuthorizeURL =
'https://www.dropbox.com/oauth2/authorize'
self.OAuthParms.pAccessTokenURL = 'https://api.dropboxapi.com/oauth2/token'
return net:notok
This reduces the code the user has to set in their own program to a
minimum.
In your class you will be able to access all the necessary components of
OAuthParms. For a list of the fields in this group see
OAuthParametersGroup.
It is likely that for most classes only the
OAuthParms.rToken
(aka the AccessToken) will be required.
In the application the user will need to populate the UserLogin method as
described above.
OAuthParametersGroup
To use a service you need to login to the service. The
OAuthLogin procedure will do this for you. This procedure takes a single
parameter, a group of type OAuthParametersGroup. All you need to do is
populate the fields in the group according to the requirements of the
service you are connecting to, then pass the group to that OAuthLogin
procedure.
The oAuthParametersGroup is declared in
netall.inc.
If you are using a class which is
aware of
NetOAuth then you may only need to set a small subset of the fields.
Consult the documentation of that class to be sure.
In the oAuthDemo apps there are example settings for ten different
services.
Name |
Type |
Description |
pServiceName |
String(100) |
The (human readable) name of the service you are connecting to.
This will be displayed to the user, and can be used when storing
the returned values. |
pOAuthVersion |
Long |
The OAuth version that the service you are connecting to
supports. Possible values are 1 or 2. If the service supports both
then set this to 2. |
pClientID |
String(256) |
The Client Secret as provided to you when you registered
your app on the service. The exact terminology used varies
from service to service, but usually includes the term Client ID
or App ID. |
pClientSecret |
String(256) |
The Client Secret as provided to you when you registered
your app on the service. The exact terminology used varies
from service to service, but usually includes the word Secret or
Password. Some examples of this terminology are App Secret,
Consumer Secret, Client Secret or Password. |
pRedirectURL |
String(256) |
The Redirect URL as provided by you to the service when you registered your app on the service.
For Desktop: In almost all cases you want to keep this simple and
set it to http://localhost. If this
is not permitted by the service then any legal url, starting with
HTTPS will do. For example https://www.somewhere.com
- you do not need to actually do anything at that URL, the app
never goes there.
For Web: You will enter the complete URL for your
oAuthLoginWeb form (https://yourdomain/oAuthLoginWeb) here. Note
that you will also need to register this URL with the service as
an allowed Redirect URL for your service.
Tip: some services (like
Facebook) add a trailing / to the URL you enter. If they do, then
it's important to include this in this string, or the login will
likely fail. |
pNoRedirectOnRefresh |
Long |
Usually when requesting a Refresh token a redirect_uri parameter
is passed to the service. In some cases this is not allowed by the
service, and it has to be suppressed. Set this property to true if
this affects your service. |
pScope |
String(4096) |
Required by some services, not required by others. Typically
identifies the specific API's that your app will use when
connecting to the service. The user will be asked to grant your
app permission to these API's when they log in. Services that have
a very limited API set typically do not need this to be set. |
pState |
String(256) |
A unique (random) value which helps to ensure that a user, not a
malicious script, is making the Redirect call. If you leave this
blank a random value will be inserted for you. |
pAuthMethod |
Long |
Set to either Net:WebPOSTAuthentication
(the default value) or Net:WebBasicAuthentication.
This determines the authorization method when doing a token
request. |
pResource |
String(2048) |
A resource parameter required by some services. |
pRequestTokenPost |
Long |
Usually set to false. Set this to true if the service requires that the
call to the RequestToken be a POST instead of the usual GET. |
pRequestTokenURL |
String (256) |
This is only required by services that log in using OAuth 1a.
This URL is specific to the service and is usually provided by the
service on either their OAuth documentation page, or with your
application details when you registered
your app on the service. |
pAuthorizeURL |
String(256) |
This URL is specific to the service and is usually provided by
the service on either their OAuth documentation page, or with your
application details when you registered
your app on the service. |
pAccessTokenURL |
String(256) |
This URL is specific to the service and is usually provided by
the service on either their OAuth documentation page, or with your
application details when you registered
your app on the service. This is sometimes referred to as
the ExchangeURL by some services. |
pAccessTokenGET |
Long |
Set this to true to make the Access Token URL to a GET request
instead of a POST request. Currently OAuth 2 only. |
pRefreshTokenURL |
String (256) |
If the service uses a different URL for refresh tokens, then
enter the value here. If nothing is set here then the
pAccessTokenURL is used. |
pRefreshTokenGET |
Long |
Set this to true to make the Refresh Token URL to a GET request
instead of a POST request. Currently OAuth 2 only. |
pExpectedCertificateCommonName |
String (256) |
When making a TLS connection the HostName part of the URL you
are connecting to is supposed to match the certificate on that
site. For some services the name does not match, but it is a known
alternate name. For example when connecting to Flickr.com
the certificate is for yahoo.com.
Turning off the name check completely can lead to a possible
man-in-the-middle attack. To avoid this, this property allows you
to set the expected name. The connection will always test the
correct name first, so if the site does change to a correct
certificate this setting will do no harm. |
pDontVerifyRemoteCertificateCommonName |
Long |
Some services do not use a correct certificate, in that the
common name for the certificate, and the URL for the API do not
match. If this is the case then set this field to true. |
pDontVerifyRemoteCertificateWithCARoot |
Long |
Some services do not use a correct certificate, in that the
certificate they are using is not in the normal chain of trust.
This can be fixed by either adding their root certificate to the
caroot.pem file, or by setting this option to true.
|
pForce |
Long |
If this is true then a new token will be fetched, even if the
current token is still valid. |
pExternalBrowser |
Long |
If this is set to netOAuth:OnScreenHTML
(the default) then the login will take place via an HTML control
on the login window.
If this is set to netOAuth:UseLocalBrowser
then the HTML control on the screen will be ignored, and the login
will take place in a browser window external to the program. The
program will open this browser window when necessary. The user
will login, and control will be returned to the program. This
should be used when the service does not support the HTML control
being used on the window.
If this is set to netOAuth:UseRemoteBrowser
then the OpenRemoteBrowser method will be called, and a message
displayed to the user. By default this method copies the URL to
the clipboard, and asks the user to paste it into their local
browser. |
pCodeChallengeMethod |
String(20) |
Some services use different code-challenge methods as part of
the PKCE flow. Set to one of 'plain'
or 's256' if using PKCE flow. |
pAccessType |
String(256) |
Some services need an access_type parameter when getting the
Authorization code. Set the value here, usually to 'offline'
if the server uses it. |
pPrompt |
String(256) |
Some services use a parameter called prompt when getting the
Authorization code. some possible values include 'none',
'consent' and 'select_account'. |
pLoginHint |
String(256) |
Some services use a login_hint parameter when getting the
Authorization code. |
pDomainHint |
String(256) |
Some services use a domain_hint parameter when getting the
Authorization code. |
pListenPort |
Long |
Only used if pExternalBrowser is not set to netOAuth:OnScreenHTML.
Set this to the listening port when an External browser is being
used. this must match the port specified in the pRedirectURL
(which must match the port registered with the service) |
pListenTLS |
Long |
Only used if pExternalBrowser is not set to netOAuth:OnScreenHTML.
Set this to true if the listening connection needs to be secure.
Typically only set if pExternalBrowser is set to netOAuth:UseRemoteBrowser
or if the service requires that the callback URL be secure. |
pListenDomain |
String(256) |
Only needs to be used if pListenTLS
is set to true. This sets the name (and path)
for the certificate for this listening port. Two files will be
loaded, the pListenDomain.CRT and
the pListenDomain.KEY files. The
domain must match the name set inside the certificate. |
pListenBindIP |
String(256) |
Only used if pExternalBrowser is set to netOAuth:OnScreenHTML.
Set this to localhost if the
browser is local, or leave it blank, or tie it to a specific IP
address of the machine the program is running on if the external
browser is on a different machine.. |
pGrantType |
String(256) |
If left blank then this defaults to 'authorization_code',
which is the most common grant type. Some services however only
implement the 'client_credentials'
grant type in which case this field should be set to that. A third
type 'password' is also supported.
See also Client Credentials
and Password Grant Types |
pTokenAccessType |
String(256) |
Some services make use of an additional parameter
(token_access_type) when requesting refresh tokens. For example
DropBox uses token_access_type=offline to get long-lived refresh
tokens. (so then this parameter would be set to offline.) |
pUserData |
&StringTheory |
Not used by the NetOAuth Class. Allows you to add extra data to
the group if you wish (ie pass extra information into the
OauthLogin procedure etc.) You need to NEW and DISPOSE this field
before and after using it. |
pUser |
String(256) |
Used only when the pGrantType is set to password.
|
pPassword |
String(256) |
Used only when the pGrantType is set to password.
|
rExpiresDate |
Long |
A Clarion date when the rToken value
will expire. |
rExpiresTime |
Long |
A Clarion time when the rToken value
will expire. |
rRealmId |
String(256) |
Returned by some servers. You may need this when making API
calls to the service. |
rRefreshToken |
String(2048) |
A refresh token from the server. This token
can be used to (silently) get another token when the original
token expires. This is done automatically for you. |
rToken |
String(2048) |
Also known as the Access Token, this is the
most important result from the call to OAuthLogin. It is used by
both OAuth1 and OAuth 2 API's. |
rTokenSecret |
String(256) |
The Token Secret is only set when accessing an OAuth 1a service.
It will be needed by the class when calling the
CreateAuthorizationString1 method (which will need to be done
before all calls to the WebService.) |
rAuthVerifier |
String(256) |
The Auth Verifier is only set when accessing an OAuth 1a
service. It will be needed by the class when calling the
CreateAuthorizationStringOauth1 method (which will need to
be done before all calls to the WebService.) |
rCode |
String(2048) |
Only in OAuth2, but not used outside the NetOauth class. It is
included here only for the sake of completeness. |
Register Your App with the Provider
There are lots of OAuth providers, and they all have
slightly different sign-up mechanisms, but the basic workflow is the same.
All of them will require you to register your application, choose which
API(s) the program will be using, and determine the permissions that your
program will need. The user will need to accept these permissions so
keeping them as minimal as possible is a good idea.
Dropbox
The Dropbox OAuth Documentation can be found here;
https://www.dropbox.com/developers/reference/oauth-guide
Dropbox requires you to register as a developer, and also register your
application which will be using the Dropbox API.
This will allow your application to access the Users' Dropbox folder and
files. (They will need to give explicit permission for your app to do
this.)
Register your App with Dropbox
- Log into Dropbox in a browser, using your own Dropbox ID
- Go to https://www.dropbox.com/developers/apps
- Click on the Create App button
- If you have not yet verified the email address associated with
your Dropbox account, then you will need to do that now. If your
email address is already authenticated then move on to the next
step.
- Select the appropriate API (usually the Dropbox API), the
appropriate access requirements (usually just an App Folder), and
give the app a name. Click on the Create button. You need to do
this step even if your app won't actually use Dropbox directly,
you only want users to be able to authenticate via Dropbox.
- At this point you will be able to see your App Key, and App
Secret. You will need these when completing the
OAuthParametersGroup.
- Desktop: For the Redirect URL enter http://localhost
Hint: You will need to click on
the Add button to add the URL to the list.
Web: For the Redirect URL enter your domain and oAuthLoginWeb -
for example
https://whatever.com/oAuthLoginWeb
- If you wish, you can go to the Branding tab and set branding
items there that you wish the user to see when logging in.
Google
The Google OAuth documentation can be found here;
https://developers.google.com/identity/protocols/OAuth2
Google requires you to register as a developer.
Register your App with Google
- Log into Google using your own Google login and Password
- Go to the Google Console at
https://console.developers.google.com
- Go to the Credentials tab (Hint: It might be under the fly-in
menu on the left) and click on the Create Credentials button to
create a new application.
- Select the OAuth Client ID option.
- Set the Application Type to be a Web Application. Give it a
name. In the Authorized Redirect URL's option put
http://localhost:8123
If you are updating an existing listing with Google, and you had http://localhost in the past, then add http://localhost:8123 as a second option.
- Click on the Create button.
- Your Client ID and Client Secret will be displayed. You will
need these when completing the
OAuthParametersGroup.
- Go to the Credentials tab, to the OAuth Consent screen tab, and
enter your details there.
- Click on the Library tab to set the APIs that the login will
use. After selecting them note the Enable button at the top of the
screen. You need to press that to enable the API.
- The Scope parameter will need to be set to match the APIs you
have selected. For a list of possible Scope values see
https://developers.google.com/identity/protocols/googlescopes
Facebook
Microsoft
You will need to register your application
Register your App with Microsoft
- Log into Microsoft here https://apps.dev.microsoft.com/
using your Microsoft login and Password.
- You will then be on the My Applications window (or go here https://apps.dev.microsoft.com
)
- Click on Add An App
- Give the application a name and a contact email.
- Tick OFF Guided Setup
- Press the Create Button
- The page will now show you the Application ID. You will need
this when completing the OAuthParametersGroup.
- Click on Generate New Password. You will need this when
completing the OAuthParametersGroup.
- Click on Add Platform, Choose Web
- For Redirect URL's click on Add URL and (for desktop) enter http://localhost
For web enter the full path to your oauthLoginWeb procedure, for
example https://somewhere.com/oAuthLoginWeb
- Click on SAVE at the bottom of the page.
Email via Outlook.com / Office365.com
You will need to register your application
Register your App with Azure
- Log into the Azure portal here https://portal.azure.com
using your Microsoft login and Password.
- You will then be on the Azure Home window (or go here https://portal.azure.com/#home
)
- Click on the Manage Azure Active Directory (actually the View
button), (or go here https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/Overview)
- In the LEFT menu is an option, App registrations (https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps)
- Edit an existing app, or add a new application (New Registration
button).
- Give the app a name.
- Select supported account types. I recommend "Accounts in any
organizational directory (Any Azure AD directory - Multitenant)
and personal Microsoft accounts (e.g. Skype, Xbox)".
- Set the Redirect URL. This is typically http://localhost:8123
. This is the default redirect URL as used by the class. You can
add more URL's if you need to using step 10 below.
- Click the Register button. The app has now been added, and you
should see the;
Application (client) id. Copy that somewhere, we'll need it in a
minute.
- Click on Redirect URIs to add another URL (as per step 8 above).
- Click on save, then return to the Overview page (see menu on
left).
- Add some client credentials. (Certificates and Secrets menu on
the Left).
- New Client Secret link.
- Make a note of the Value - they'll get used in a bit. (hint,
once you leave this page you can't see the value again, so grab it
now.) It's the Value you want, not the Secret ID.
- Click on the API Permissions on the Left Menu.
- Add a Permission button. Want to Add Microsoft Graph. (It's the
first option offered, right at the top, triple the size of the
other options.)
- Select Delegated Permissions
- Must have offline_access , SMTP -> SMTP.Send (optional for
sending), POP -> POP.AccessAsUser.All (optional for receiving),
IMAP -> IMAP.AccessAsUser.All (optional for IMAP).
Xero
A walkthrough of the Zero signup occurred in the
NetTalk
User Group Webinar for Feb 11, 2021 , from around the 0:24 minute
mark.
Xero is an online accounting system.
It contains an API that lets programs interact with the data set. So,
for example, your program might post invoices directly into Xero.
NetOAuth doesn't implement the Xero API, this document just contains the
workflow to logging into Xero, so that you can implement the API in the
normal way from there. For more on the Xero partner program see
https://developer.xero.com/partner/
.
Register as an App Partner
Register your App with Xero
Yahoo
Hint: Although
all Yahoo services make use of the Yahoo Login, not all of them support
OAuth2. Some (like Flickr) are still on OAuth 1a.
Register your App with Yahoo
- Log into Yahoo with your normal Yahoo account.
- Add your application here https://developer.yahoo.com/apps/create/
- Set the application type to "Installed Application".
- Set the callback domain to something like capesoft.com.
Yahoo does not support Localhost here.
- Select the API's you want to consume with this app.
- Click on the Create App button.
- This should take you to the app screen. You will need these when
completing the OAuthParametersGroup.
- You can return to your list of Yahoo Apps later on by going
here.
hhttps://developer.yahoo.com/apps/ . This will allow you to
see your Client ID and Client Secret again.
Flickr
Although Flickr is a Yahoo property, the Flickr API
is separate from the Yahoo API.
Register your App with Flickr
- Log into Flickr with your Yahoo account.
- Go to the Flickr developer home page here ; https://www.flickr.com/services/developer
- Click the API link at the top of the page
(https://www.flickr.com/services/developer/api/)
- Click the Request an API key link.
(https://www.flickr.com/services/apps/create/)
- Click the Request an API link. (yeah, again)
- Choose Non-Commercial or Commercial.
- Enter your application name, and description. Set the App type
to Web Application, and in the Callback URL enter http://localhost
- When the form is complete click on Submit.
- Make a note of the Key and Secret. You will need these when
completing the OAuthParametersGroup.
- Click the Edit Authentication Flow link.
- Set the App Type to Desktop Application, Enter a logo and
description if you like. Click on Save Changes.
Quickbooks (Intuit)
LinkedIn
Register your App with LinkedIn
- Log into Linked In
- Go to https://www.linkedin.com/secure/developer
- Click on Create Application button
- Fill in the various details and click OK.
- The Authentication Keys will be displayed. You will need these
when completing the OAuthParametersGroup.
- Add callback domains under the Auth tab (http://localhost
and http://localhost:8123) and click
on the Update button.
Instagram
Register your App with Instagram
- Log into Instagram
- Go to https://www.instagram.com/developer/
- Click on the Register Your Application button
- Fill in the various details and click OK.
- Go to the Manage Clients tab, and click on the Register a new
Client button.
- Enter your details. For Valid redirect URIs put http://localhost
- Once everything is filled in click on the Register button.
- The application should now be in the list of clients. Click on
the Manage button for the app.
- The Client ID and Client Secret are here. You will need these
when completing the OAuthParametersGroup.
Using an External Browser to Login
Up until January 2021 it was possible to log into any
service from the Chrome Explorer control in your program. However in
January 2021 Google decided to
ban this practice and only allow logins to take
place outside the program, in a separate browser. While this is a less
elegant approach for the user, it does provide some security benefits. So
from NetTalk 12.11 it is possible to adopt this approach, and set the
login to occur externally.
Note: There are changes in the OAuthLogin procedure to support External
Browser Logins. To upgrade your program to make use of this feature
re-import the procedure into your application by importing the procedure
from one of the examples.
This approach can be used for any service, and removes the need to have an
HTML control in the program at all. For most services an embedded control
is more elegant, and does not have the requirement of a separate (working,
modern) browser on the users' computer, but it is no longer a requirement.
External Browser on the Same
Machine
In the simplest case the user's current browser is simply spawned with
the login page to the service. Once the user has logged in control
returns to the program, and the OAuth login completes in the normal way.
The only requirement here is that the user has a (default, modern)
browser installed and working on the machine. To make this happen three
parameters are set before calling the OAuthLogin procedure
OAuthParms.pExternalBrowser =
netOAuth:UseLocalBrowser
OAuthParms.pListenTLS = false
OAuthParms.pListenPort = 8123
OAuthParms.pListenBindIP = '127.0.0.1'
In order to use this approach the browser has to be able to transfer
control back to the program. This means that the OAuthLogin procedure is
listening on a port for the browser
[1].
It is highly unlikely it will be able to listen on port 80. For this
reason it will be listening on another port (say 8123). So the pRedirect
property will need to be set to this port. For example;
OAuthParms.pRedirectURL =
'http://localhost:8123'
This in turn means that this URL (including the port number) will need
to be registered with the service you are connecting to.
Google
See
Google for an example.
Google allows for multiple RedirectURL's to be set, so you can update,
or better yet add to the setting via the
Credentials page. Google is still allowing old
accounts to use the in-program logins, so leave the older (localhost)
setting there as well for now.
Note 1: Although the
browser is connecting back to a "web server" the listening object is
based on the NetSimple class, not the NetWebServer class. The listener
is only listening for something very specific, so it does not need to be
a full-fledged web server, and NetTalk Server level is not required.
External Browser on a
Different Machine
In some situations it is not possible to spawn a browser on the same
machine as that would be a security hazard for that machine. For example
a shared cloud server, where the application is being accessed via RDP
or similar method and launching a separate (uncontrolled) browser on the
machine is not tenable.
In this situation the user has to login on a different machine, and then
that login is used to complete the OAuth flow in the program. In order
to accomplish this there are two (relatively) complicated steps that
need to be solved;
- Passing the URL to the user's browser
- Allowing the program (on the server) to listen to a valid
RedirectURL
1. Passing the URL from the program to the user's browser.
The best mechanism for starting a browser on
another computer will depend a lot on what remote access protocol you
are using, and what that protocol allows you to do. By default the
OAuthLogin procedure simply copies a URL into the clipboard, and asks
the user to execute that URL in their local browser.
If you wish to add code to this process, to make it more automatic (if
your RDP protocol allows for that) then you can embed the code into
the OAuthLogion procedure, into the OpenRemoteBrowser
method.
2. Redirect URL
When the user completes the login on their computer, the login page has
to redirect back to your actual running program (the one running on say
the Cloud server). It has to be able to make a connection to this
program - there is unforunately no way around that. To make matters a
bit more complicated the connection will need to be over HTTPS, in other
words a secure connection, and this in turn means that the program will
need a valid web certificate.
- The server will need a DNS name which can be used so that the
service can redirect back to this server.
- The server will need to be listening on a port (423 by default,
but any port will do) and an incoming route will need to be open to
this port. Incidentally the program is only listening on this port
while the user is logging in.
- The service will need to be set to allow this DNS name and port to
be permissible as a RedirectURL.
- Assuming this machine is shared by many users, only one user can
log in at a time, since only one instance of the program can listen
on the same port at one time. However if the users are sharing a
Google account then only one needs to login anyway so this isn't a
big issue.
- The listening server (in the OAuthLogin) procedure needs to be
initialized with details of the server-side certificate.
An example of the parameters to set, before calling OAuthLogin are as
follows;
OAuthParms.pExternalBrowser =
netOAuth:UseRemoteBrowser
OAuthParms.pListenTLS = true
OAuthParms.pListenPort = 8423
OAuthParms.pListenDomain = 'cloud.capesoft.com'
OAuthParms.pListenBindIP = ''
Using in a Web Server
To this point the discussion has revolved around using
OAuth authentication in a desktop program. It's possible however that you
will want to make use of external APIs from a Web server program. For
example, you may want to allow a user on your server to archive reports to
say Dropbox. To do this the user has to log into drop box, and then the
Server can copy the file there.
Ground Rules
- Chrome Explorer / File Explorer are not required
- Your server will (almost certainly) need to be HTTPS. It's
unlikely the remote service will tolerate it not being HTTPS.
Class Reference
NetOAuth
Included in NetTalk
Desktop
Derivation
- NetOAuth ( NetOAuth.Inc / NetOAuth.Clw
)
Properties
Property |
Description |
Parms OAuthParametersGroup |
A pointer to the Parms group passed to the INIT method. |
Methods
Method |
Description |
ConstructBrowserReply |
Called when the login is being made via an external
browser, and the external browser has completed the login.
This is the HTML reply sent to the browser. |
Done |
Called when the login is complete. |
ErrorTrap |
Called when an error occurs. |
HandleRedirectURL |
Called when the File Explorer control is complete, and the
service is calling the Redirect URL. |
Init |
Primes the object ready for the login. |
OpenBrowser |
Calls the local, external browser, with the URL so the
user can login. |
OpenRemoteBrowser |
Copies the URL to the clipboard so it can be pasted in a
remote browser |
PageReceived |
Is called when incoming request to the OAuth server are
completed. A single login typically spans multiple requests,
and responses to the server. |
ProcessBrowserRedirect |
The reply received from the remote browser |
SendBrowserReply |
The page to send to the browser to answer the browser's
redirect request. |
StartAuth |
Starts the OAuth process. |
UserLogin |
Transfers control back from the object to the calling
procedure. Typically triggers the File Explorer control with
the passed URL. |
ConstructBrowserReply
ConstructBrowserReply
(Stringtheory rReply,String pInfo)
Description
This method sends the final HTML back to the browser if an external
browser is being used to login. It defaults to a simple message. If
you want the page to be more elaborate then you can replace this
method in the OauthLogin procedure.
Parameters
Parameter |
Description |
rReply |
A StringTheory object containing the HTTP header, and HTML
content to send to the browser after the login process has
been completed. |
pInfo |
A message generated in the code, depending on where this
method is called from. |
Return Value
Nothing. The result of the method is placed in the rReply parameter.
See Also
Using an External Browser to Login,
OpenBrowser,
OpenRemoteBrowser,
ProcessBrowserRedirect,
SendBrowserReply
Done
Done ()
Description
This method is called when a login is complete.
Notes
The OAuthDemo procedure uses this method to save the various tokens.
It also displays a message to the user, and closes the login window.
Return Value
The method returns nothing.
See Also
ErrorTrap
ErrorTrap
ErrorTrap
(string ErrorStr, string FunctionName)
Description
ErrorTrap is called if a communications error occurs, or if a request
is incomplete in some way.
Parameters
Parameter |
Description |
ErrorStr |
A description of the error |
FunctionName |
the name of the method where the error occured. |
Notes
You will need to add any error handling code into this method.
Return Value
The method returns nothing.
See Also
Done
HandleRedirectUrl
HandleRedirectUrl
(string pUrl)
Description
This method is called by the
FileExplorer
EventNavigateComplete2 method when the service calls the
Callback URL.
Parameters
Parameter |
Description |
pURL |
The callback URL as set by the remote service. |
Notes
The callback URL contains various interim results from the login
process. This method passes control back to the OAuth object where
further interactions with the remote server can take place. If
everything is successful then the process will complete in the Done
method.
Return Value
The method returns 0 if it was successful. It returns a non-zero value
(and
ErrorTrap is called) if the URL
being received was not complete.
See Also
UserLogin ,
ErrorTrap,
Done
Init
Init
(*OAuthParametersGroup pParms)
Description
This method sets up the object so that it is ready to do a login. The
various fields in the pParms group need to be set correctly for the
login to work. For more information on the settings see
here.
Parameters
Parameter |
Description |
pParms |
Contains all the properties necessary to call the service.
For more information on the properties see the section OAuthParmetersGroup.
|
Notes
The parms parameter also contains the return values as returned by the
service.
Return Value
The method returns a long. If set to 0 then the login was succesful,
if set to not zero then the login failed.
See Also
StartAuth
OpenBrowser
OpenRemoteBrowser
PageReceived
PageReceived()
Description
The login process with the server typically spans several requests and
responses with the server. This method handles each response and
determines what step to make next. You do not need to embed anything
in this method.
Return Value
The method returns nothing.
See Also
ErrorTrap
ProcessBrowserRedirect
ProcessBrowserRedirect
(Net:SimplePacketType pPacket)
Description
When the user has completed the login process in the external browser
(local or remote) then the browser will send a URL back to the
program. This is the "redirect" - the browser is redirecting traffic
back to your program. At this point that data must be processed, and
the process of getting a OAuth token continues.
Parameters
Parameter |
Description |
pPacket |
The raw packet as received from the browser. This will
include the HTTP headers, and any other data. |
Return Value
Nothing.
See Also
Using an External Browser to Login,
OpenBrowser,
OpenRemoteBrowser,
ConstructBrowserReply,
SendBrowserReply
SendBrowserReply
SendBrowserReply
(NetSimple pListener,String pInfo)
Description
When a browser makes a request (as it did with the redirection call)
then it needs to get a reply, or it sits around just waiting. A small,
generic reply is created with this method and sent back to the
browser.
Parameters
Parameter |
Description |
pListener |
The name of the NetSimple object which is listening for the
browser redirect. |
pInfo |
A simple string to include in the HTML reply. This will be
visible to the user. |
Return Value
Nothing
See Also
Using an External Browser to Login,
OpenBrowser,
OpenRemoteBrowser,
ProcessBrowserRedirect,
ConstructBrowserReply
StartAuth
StartAuth ()
Description
This method starts the authentication process. It needs to be called
after the call to the Init method.
Notes
This starts the process, and the OAuth object has control. When it is
ready to do so the object hands back control to the File Explorer
object by calling the UserLogin method. Control will then return to
the OAuth object via the HandleRedirectUrl method.
Return Value
The method returns nothing.
See Also
Init,
UserLogin,
HandleRedirectUrl
UserLogin
UserLogin
(String pUrl)
Description
This method is called when control returns from the OAuth object to
the File Explorer control on the window. The URL parameter indicates
the URL that should be loaded by the File Explorer control.
Parameters
Parameter |
Description |
pUrl |
The URL that the File Explorer control should load. |
Notes
This call starts the sequence where the user interacts with the remote
service directly via the HTML control on the window. The user will
remain in this control until the service indicates it is done by
redirecting to the callback URL. This is detected by the File Explorer
object, and control is returned to the object via the
HandleRedirectUrl
method.
Return Value
The method returns nothing.
See Also
HandleRedirectURL
[End of this document]