OAuth
CapeSoft Logo

CapeSoft NetTalk
OAuth

Download Latest Version
Installed Version Latest Version

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;
  1. Create an account at the service
  2. Register the app on the service
  3. Gather (or set) the vital settings the program will need.
  4. 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
! forces a new login, rejects stored login
OAuthParms.pExternalBrowser = netOAuth:UseLocalBrowser
! forces the login via an external browser, not the HTML control on the window.
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;
  1. There's no need to have File Explorer in the Web Server app.
  2. 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).
  3. 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.
  4. 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;
  1. On the Button tab, the Type is set to OAuth Login
  2. 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;
  1. 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.
  2. 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.
  3. 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.)
  1. 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) ! call this first

    self.OAuthParms.pClientId = '***some client id***' 
    ! specific to this application
    self.OAuthParms.pClientSecret = '***some secret***'
    ! specific to this application

    ReturnValue = OAuthLogin(self.OAuthParms)
    ! this is the OAuthLogin proc in your app created earlier.

    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;
  1. At the top of the include file include the NetOAuth.Inc file

    include('NetOAuth.Inc'),Once
  2.  A Property in the app called OAuthParms (or similar) of type Group(OAuthParametersGroup).

    OAuthParms Group(OAuthParametersGroup).
  3. 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 
    ! the derived method needs to set this to ok if it is successful there.

    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

  1. Log into Dropbox in a browser, using your own Dropbox ID
  2. Go to https://www.dropbox.com/developers/apps
  3. Click on the Create App button
  4. 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.
  5. 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.
  6. At this point you will be able to see your App Key, and App Secret. You will need these when completing the OAuthParametersGroup.
  7. 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
  8. 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

  1. Log into Google using your own Google login and Password
  2. Go to the Google Console at https://console.developers.google.com
  3. 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.
  4. Select the OAuth Client ID option.
  5. 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.
  6. Click on the Create button.
  7. Your Client ID and Client Secret will be displayed. You will need these when completing the OAuthParametersGroup.
  8. Go to the Credentials tab, to the OAuth Consent screen tab, and enter your details there.
  9. 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.
  10. 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

The developer page for Facebook is at https://developers.facebook.com/docs/facebook-login/web

Register your App with Facebook

  1. Log into Facebook using your normal account.
  2. Go to https://developers.facebook.com/apps/
  3. Click the Register Now button to register as a Facebook developer.
  4. Once you are Registered you can register an app by clicking on the Create App ID button.
  5. On the left of the window is the menu. Click on the Settings tab. You will need these when completing the OAuthParametersGroup.
  6. Click on the Add Platform button. Choose Web site.

Microsoft

You will need to register your application

Register your App with Microsoft

  1. Log into Microsoft here https://apps.dev.microsoft.com/  using your Microsoft login and Password.
  2. You will then be on the My Applications window (or go here https://apps.dev.microsoft.com )
  3. Click on Add An App
  4. Give the application a name and a contact email.
  5. Tick OFF Guided Setup
  6. Press the Create Button
  7. The page will now show you the Application ID. You will need this when completing the OAuthParametersGroup.
  8. Click on Generate New Password. You will need this when completing the OAuthParametersGroup.
  9. Click on Add Platform, Choose Web
  10. 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
  11. 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

  1. Log into the Azure portal here https://portal.azure.com  using your Microsoft login and Password.
  2. You will then be on the Azure Home window (or go here https://portal.azure.com/#home )
  3. Click on the Manage Azure Active Directory (actually the View button), (or go here https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/Overview)
  4. In the LEFT menu is an option, App registrations (https://portal.azure.com/#view/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/~/RegisteredApps)
  5. Edit an existing app, or add a new application (New Registration button).
  6. Give the app a name.
  7. Select supported account types. I recommend "Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)".
  8. 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.
  9. 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.
  10. Click on Redirect URIs to add another URL (as per step 8 above).
  11. Click on save, then return to the Overview page (see menu on left).
  12. Add some client credentials. (Certificates and Secrets menu on the Left).
  13. New Client Secret link.
  14. 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.
  15. Click on the API Permissions on the Left Menu.
  16. 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.)
  17. Select Delegated Permissions
  18. 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

  1. Go here to register as an app partner - https://developer.xero.com/partner/app-partner (scroll down to the bottom of the page to do the actual registration)

Register your App with Xero

  1. The getting started guide for Xero is at https://developer.xero.com/documentation/getting-started/getting-started-guide .
  2. First sign up to the API here - https://www.xero.com/za/signup/api . Once this is completed you will get an email verification.
  3. Click on the link in the email to set a password for your account.
  4. You will then see a form to "Add your Organization to Xero now". DON'T DO THIS. Rather click on the (very small) link to "Try the Demo Company"
  5. Add an application to Xero here - https://app.xero.com/Application/Add
    For the OAuth callback domain enter
    localhost
  6. You can choose the Auth Code or PKCE flow, both are supported.
  7. The screen will now display the Consumer Key, and Consumer Secret. You will need these when completing the OAuthParametersGroup.

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

  1. Log into Yahoo with your normal Yahoo account.
  2. Add your application here https://developer.yahoo.com/apps/create/
  3. Set the application type to "Installed Application".
  4. Set the callback domain to something like capesoft.com. Yahoo does not support Localhost here.
  5. Select the API's you want to consume with this app.
  6. Click on the Create App button.
  7. This should take you to the app screen. You will need these when completing the OAuthParametersGroup.
  8. 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

  1. Log into Flickr with your Yahoo account.
  2. Go to the Flickr developer home page here ; https://www.flickr.com/services/developer
  3. Click the API link at the top of the page (https://www.flickr.com/services/developer/api/)
  4. Click the Request an API key link. (https://www.flickr.com/services/apps/create/)
  5. Click the Request an API link. (yeah, again)
  6. Choose Non-Commercial or Commercial.
  7. 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.
  8. Make a note of the Key and Secret. You will need these when completing the OAuthParametersGroup.
  9. Click the Edit Authentication Flow link.
  10. Set the App Type to Desktop Application, Enter a logo and description if you like. Click on Save Changes.

Quickbooks (Intuit)

Intuit developer page is at https://developer.intuit.com/
Create a developer account.
The list of your Intuit apps is at https://developer.intuit.com/v2/ui#/app/dashboard . The first time you go here you will be prompted to create your first app.
Intuit OAuth documentation is at https://developer.intuit.com/docs/0100_quickbooks_online/0100_essentials/000500_authentication_and_authorization/connect_from_within_your_app 

Register your App with Intuit

  1. Go to https://developer.intuit.com/v2/ui#/app/startcreate
  2. In the "Just Start Coding" option click on the Select API's button.
  3. Select the API's you want to use
  4. Click on the Create App button
  5. Go to the My Apps list (https://developer.intuit.com/v2/ui#/app/dashboard)
  6. Click on the app you just made (likely called Untitled)
  7. Click on the Settings tab. Give the App a name. Set Single Sign on to No.
  8. Click the Save button (top right corner of the screen)
  9. On the Keys tab make a note of the OAuth Consumer Key and OAuth Consumer Secret fields. You will need these when completing the OAuthParametersGroup.

LinkedIn

Register your App with LinkedIn

  1. Log into Linked In
  2. Go to https://www.linkedin.com/secure/developer
  3. Click on Create Application button
  4. Fill in the various details and click OK.
  5. The Authentication Keys will be displayed. You will need these when completing the OAuthParametersGroup.
  6. 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

  1. Log into Instagram
  2. Go to https://www.instagram.com/developer/
  3. Click on the Register Your Application button
  4. Fill in the various details and click OK.
  5. Go to the Manage Clients tab, and click on the Register a new Client button.
  6. Enter your details. For Valid redirect URIs put http://localhost
  7. Once everything is filled in click on the Register button.
  8. The application should now be in the list of clients. Click on the Manage button for the app.
  9. 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

external browser on 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

external browser on same 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;
  1. Passing the URL to the user's browser
  2. 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.
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

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

OpenBrowser (String pUrl)

Description

This method calls an external browser (on the same machine) with a URL. It is used when the pExternalBrowser property is set to netOAuth:UseLocalBrowser.

Parameters

Parameter Description
pUrl The URL to call from the external browser to the OAuth Service to start the login.

Return Value

The result of the call to ShellExecuteA. See here for a list of possible return values.

See Also

Using an External Browser to Login, OpenRemoteBrowser, ProcessBrowserRedirect, ConstructBrowserReply, SendBrowserReply

OpenRemoteBrowser

OpenRemoteBrowser (String pUrl)

Description

This method copies the remote browser URL to the clipboard. If your remote access protocol supports a better way of launching a browser on the user's local desktop then add code into this method to do that.

Parameters

Parameter Description
pUrl The URL to call from the external browser to the OAuth Service to start the login.

Return Value

net:ok

See Also

Using an External Browser to Login, OpenBrowser, ProcessBrowserRedirect, ConstructBrowserReply, SendBrowserReply

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]
Return to NetTalk Documentation Index