To successfully authenticate a service (server side) to connect (as a
service client) to another service protected by an access token, you will need to implement OAuth
this way.
Before you begin:Before you begin, you must have an account with an OpenID
Connect/OAuth2 provider that will provide authentication services for you.
Determine which
single sign-on protocol the IdP uses: OpenID Connect or OAuth2. If the IdP is using the OAuth2
protocol, you will need to register the IdP's OAuth2 endpoints in the GAS. To learn about how to
check this, go to
Identify the protocol in use by IdP.
Important:
If the IdP is using the OpenID Connect protocol, there is no need to use the
ImportOAuth program as OpenID Connect has the metadata feature that allows
Genero's OpenID Connect service to automatically fetch the metadata, including all the endpoint
URLs, from the IdP. For more information on SSO implementation with OpenID Connect and OAuth2, see
OpenID Connect/OAuth2 SSO.
Go to Import IdP metadata as OAuth2 for instructions on importing the
metadata in the GAS.
About this task:In service-to-service –
also known as "machine-to-machine" – implementation, an application is authenticated with the
Identity Provider (IdP) using its Client ID and Client Secret. The IdP validates this information and returns an access
token with the scopes (permissions) you have registered for the Genero web service (server side) it
can access, and the scopes for the web service client that the web service can
access.
The stub files for both the service (server side) and the client service must
be generated with the appropriate code to handle OAuth access, taking the access token into account.
To do this, you must:
- Get an access token directly from the IdP using the GetToken
tool.
- Run the fglrestful tool with the
--oauth=yes
option and
provide the access token in the URL to generate the stub file.
You define scopes in your Genero REST web service (server side) and web
service client source files (4gl) with the WSScope
attribute.
For more information about WSScope
, refer to the WSScope topic in the
Genero Business Development Language User Guide
Alternatively, to secure legacy REST web services that do not define any
WSScope
attributes or that are written with the REST low-level API, you can set the
SCOPE
element in the configuration file (xcf). For more
information, refer to the SCOPE (for service) topic in the Genero Application Server User Guide.
The access token is provided to your application and web services via the
GAS environment at runtime. To get the access token:
- In your client application, you must register the access token with the GWS engine using
OAuthAPI.Init
.
- In your service (server side), you must retrieve the access token, using either the
fgl_getenv("OIDC_ACCESS_TOKEN
")
instruction or from the
WSContext
variable, to initiate the client service using
OAuthAPI.InitService
.
Create the Web service (server side)
-
Register the web service or APIs providing the service on the IdP site.
For more information on registering a web service, refer to the IdP documentation. Typically,
it consists of the following tasks:
-
Register the web service with the IdP.
-
Register all the scopes (permissions) that might be granted to the client.
These are the scopes you should already have defined in your web service 4GL with the
WSScope
attribute to provide security globally for the service (on the
WSInfo
record) or for its functions. You should have a list of such
WSScope
entries.
-
Register the GAS delegation service oauth2callback URL
Typically, the oauth2callback redirect URL is the URL of the OpenIDConnect service on the GAS
where the IdP will redirect the user-agent to get the OAuth2 ID token. For more information on the
callback URL, go to
GAS SSO oauth2callback redirect URL
-
Generate the stub for your Genero web service (client).
You must have the web service (client) secured by the IdP and have its scopes (permissions)
registered. You must also have deployed the web service on the GAS before carrying out these
steps.
-
Get an access token from the IdP to access the secured web service.
Use the GetToken tool. For further information on using
GetToken, go to GetToken.
(Line breaks have
been added to improve readability.)fglrun GetToken password -u user -p mypw
--idp https://my_OAuth_provider.oauth.com
--savetofile myWsClientToken.json myWSClientScope
Where:
- The password command is used to get an access token on behalf of an
authenticated user.
- The user name and password provided (
-u user -p mypw
) is that of a registered
user in the IdP.
- The URL of the IdP is specified in the
--idp
option.
- myWsClientToken.json is the filename where the access token is saved.
myWSClientScope
is the list of scopes (permissions) defined in your Genero web
service source file (4gl) with the WSScope
attribute. You
should have a list of such WSScope
entries.
You get an access token that is valid for 10 minutes. After ten minutes, you will need to query
for a new access token.
-
(Optional) Test to ensure you can access the web service with the scopes in the token.
- If your GAS is not running, start it.
- Enter the URL of the web service in your browser to get the OpenAPI documentation, adding the
token obtained in the previous step in the query:
http://myhost:6394/gas/ws/r/myGroup/myXcf/myClientService?openapi.json&access_token=token
If you can see the OpenAPI documentation displayed, you have accessed the protected
service.
-
Generate the stub with code to handle OAuth access.
Use the fglrestful tool.
(Line breaks have
been added to improve readability.)fglrestful -o ws_client
--oauth yes
--tokenfile myWsClientToken.json
http://myhost:6394/gas/ws/r/myGroup/myXcf/myClientService?openapi.json
Where:
- ws_client specifies the filename of the stub in the output
(
-o
) option.
--oauth yes
specifies that the web service is secured and code to handle OAuth
access is generated in the stub, taking the access token into account.
--tokenfile
specifies myWsClientToken.json as the file
where the token was saved.
- ?openapi.json query string gets the OpenAPI document.
The ws_client.4gl is generated from the OpenAPI document.
-
Compile ws_client.4gl.
The stub file must be imported into your web service (server side) application.
-
Code in your Genero REST web service (server side) to call your client service.
Write code in your web service 4gl module:
-
Import the client service stub file module.
IMPORT FGL ws_client
-
Import the
OAuthAPI
library.
IMPORT FGL OAuthAPI
-
Code to call the client service function.
You must retrieve the access token and initiate the client service before calling any of its
functions. The code to do this is shown in the sample function.
The access token – provided via
the GAS environment at runtime – is registered in a global variable ctx
when the
service (server side) starts, and is retrieved for forwarding to the web service client when using
OAuthAPI.InitService(5, access_token)
. For more information about
OAuthAPI.InitService
, refer to the Genero Business Development Language User Guide.
# Web service (server side module)
IMPORT FGL ws_client
IMPORT FGL OAuthAPI
PRIVATE DEFINE ctx DICTIONARY ATTRIBUTE(WSContext) OF STRING
PUBLIC FUNCTION myClientServiceCall()
DEFINE access_token STRING
DEFINE wsstatus INTEGER
DEFINE ret string
# retrieve access_token for forwarding to the client service
LET access_token=ctx["OIDC_ACCESS_TOKEN"]
# Init OAuth service
IF NOT OAuthAPI.InitService(5, access_token) THEN
RETURN "Cannot initiate OAuth service"
END IF
# Call the client service via the stub file
CALL ws_client.myFunc() RETURNING wsstatus
CASE wsstatus
WHEN ws_client.C_SUCCESS
LET ret=SFMT("Successfull ws_client call:%1",wsstatus)
OTHERWISE
LET ret=SFMT("Unexpected ws_client error :%1",wsstatus)
END CASE
RETURN ret
END FUNCTION
# Other web service (server side) functions
-
Configure your web service (server side) xcf file for delegation.
In the
DELEGATE
element, set the
service
attribute to the
Genero GeneroAccessService, and provide the URL of the IdP in the
IDP
element.
<APPLICATION Parent="ws.default" ...>
<EXECUTION>
</ENVIRONMENT_VARIABLE>
</PATH>
</MODULE>
<DELEGATE service="services/GeneroAccessService">
<IDP>my_OAuth_provider_url</IDP>
</DELEGATE>
#...
</EXECUTION>
</APPLICATION>
GeneroAccessService
is the REST web service in the
$FGLDIR that handles delegation in the service calls, and forwards the access
token if used in a call to another service.
-
Deploy and enable your service on the GAS using a Genero Archive file.
For more details of deploying and managing applications and web
services using Genero Archives on the GAS, refer to the Deploying and managing applications
with GAR section in the Genero Application Server User Guide
Your gar file must have a MANIFEST file pointing to
your web service configuration file (.xcf).
-
Deploy the gar file on the GAS.
Use the gasadmin tool; for example, gasadmin gar --deploy-archive
myServiceGar.gar
-
Enable the service on the GAS
Use the gasadmin tool; for example, gasadmin gar --enable-archive
myServiceGar.gar
-
Generate the stub for your Genero web service.
-
Get an access token to access the web service secured by the IdP.
Use the GetToken tool. For further information on using
GetToken, go to GetToken.
(Line breaks have
been added to improve readability.)fglrun GetToken password -u user -p mypw
--idp https://my_OAuth_provider.oauth.com
--savetofile mytoken.json myWSScope
Where:
- The password command is used to get an access token on behalf of an
authenticated user.
- The user name and password provided (
-u user -p mypw
) is that of a registered
user in the IdP.
- The URL of the IdP is specified in the
--idp
option.
- mytoken.json is the filename where the access token is saved.
myWSScope
is the list of scopes (permissions) defined in your Genero web
service (server side) and web service client source files (4gl) with the
WSScope
attribute. You should have a list of such WSScope
entries.
You get an access token that is valid for 10 minutes. After ten minutes, you will need to query
for a new access token.
-
(Optional) Test to ensure you can access the web service with the scopes in the token.
- If your GAS is not running, start it.
- Enter the URL of the web service in your browser to get the OpenAPI documentation, adding the
token obtained in the previous step in the query:
http://myhost:6394/gas/ws/r/myGroup/myXcf/myService?openapi.json&access_token=token
If you can see the OpenAPI documentation displayed, you have accessed the protected
service.
-
Generate the stub with code to handle OAuth access.
Use the fglrestful tool.
(Line breaks have
been added to improve readability.)fglrestful -o ws_stub
--oauth yes
--tokenfile mytoken.json
http://myhost:6394/gas/ws/r/myGroup/myXcf/myService?openapi.json
Where:
- ws_stub specifies the filename of the stub in the output
(
-o
) option.
--oauth yes
specifies that the web service is secured and code to handle OAuth
access is generated in the stub, taking the access token into account.
--tokenfile
specifies mytoken.json as the file where the
token was saved.
- ?openapi.json query string gets the OpenAPI document.
The ws_stub.4gl is generated from the OpenAPI document.
-
Compile ws_stub.4gl.
The stub file must be imported into your client application.
Create the client application
-
Create your Genero REST client application.
This is a browser-based application secured by your IdP that will provide the interface to the
web services resources and operations.
For more details on calling a web service through a client application, refer to the
Calling a web service function section in the Genero Business Development Language User Guide.
Write code in your 4gl module:
-
Import the service stub file module.
-
Import the
OAuthAPI
library.
-
In the MAIN program block, code to retrieve the OIDC IDS – provided via the GAS environment at
runtime – and initiate OAuth.
Important: Initiate OAuth firstCall the OAuthAPI.init()
function to register the access token and access information, such as subject, scopes, endpoints,
and so on, with the GWS engine before making any calls to the service functions.
IMPORT FGL ws_stub
IMPORT FGL OAuthAPI
DEFINE c_client_id STRING
DEFINE c_secret_id STRING
DEFINE my_user_id STRING
MAIN
# Init OAuthAPI
LET c_client_id = fgl_getenv("OIDC_CLIENT_ID")
LET c_secret_id= fgl_getenv("OIDC_SECRET_ID")
IF NOT OAuthAPI.Init(5, c_client_id, c_secret_id) THEN
DISPLAY "Error: unable to initialize OAuth"
EXIT PROGRAM 1
ELSE
LET my_user_id = OAuthAPI.getIDSubject
END IF
# ... calls to web service functions
END MAIN
-
On the IdP site, register your Genero application.
Single sign-on implementation may vary depending on the IdP; refer to the IdP documentation
for more information.
-
Register the web application.
-
Register the GAS delegation service oauth2callback URL
Typically, the oauth2callback redirect URL is the URL of the OpenIDConnect service on the GAS
where the IdP will redirect the user-agent to get the OAuth2 ID token. For more information on the
callback URL, go to
GAS SSO oauth2callback redirect URL
The IdP provides the CLIENT_PUBLIC_ID
and
CLIENT_SECRET_ID
that you use for requesting access tokens to the protected
resources.
-
Configure your Genero web application xcf file for delegation to the
IdP.
Add the
DELEGATE
element and set its
service
attribute to
the Genero OpenIDConnectServiceProvider. Provide the URL of the IdP and the
CLIENT_PUBLIC_ID
and
CLIENT_SECRET_ID
tokens obtained when
registering your application.
<APPLICATION Parent="defaultwa" ...>
<EXECUTION>
#...
</PATH>
</MODULE>
<DELEGATE service="services/OpenIDConnectServiceProvider">
<IDP>my_OAuth_provider_url</IDP>
<SCOPE>email</SCOPE>
<CLIENT_PUBLIC_ID>XXXXXXXX.apps.myOAUTHIdpusercontent.com</CLIENT_PUBLIC_ID>
<CLIENT_SECRET_ID>XXXXXX-XXXXXX</CLIENT_SECRET_ID>
</DELEGATE>
#...
</EXECUTION>
</APPLICATION>
The configuration differs slightly depending on the Single sign-on
protocol used by the IdP.
-
Deploy and enable your application on the GAS using a Genero Archive file.
For more details of deploying and managing applications and web
services using Genero Archives on the GAS, refer to the Deploying and managing applications
with GAR section in the Genero Application Server User Guide
Your gar file must have a MANIFEST file pointing to your application
configuration file (.xcf).
-
Deploy the gar file on the GAS.
Use the gasadmin tool; for example, gasadmin gar --deploy-archive
myAppGar.gar
-
Enable the application on the GAS
Use the gasadmin tool; for example, gasadmin gar --enable-archive
myAppGar.gar
Test your application by starting the GAS and entering the application URL in the browser. If
your browser is redirected to the IdP to enter your credentials, you have configured your
application correctly. If your credentials are valid, your browser is redirected back to the
application; otherwise an HTML error page is returned.
Troubleshooting access
- If errors are encountered accessing your service, check the logs:
vm-services-GeneroAccessService*.log, and the
AccessService.log:
For instance, if you get error 403 "Forbidden" and you
see the following message in the
AccessService.log:
ERROR : 29389 - [AccessService] "RetrieveIDPMetadata" INSERT failed :UNIQUE constraint failed: fjs_provider.issuer
Check
that the IdP's URL in the
DELEGATE
element of your web service
xcf is correct.
- If a call made to a Genero web service function fails, check the error status code returned to
the client. For example, a value of -1 indicates a failed operation. The code
-15553
with a description such as Asynchronous Connection failed
or connection timeout expired
indicates an infrastructure error. Check
that you have a call to OAuthAPI.init()
in your client application.
For more
information on handling errors, refer to the Handle REST server errors page in Genero Business Development Language User Guide
What to do next:Users also need to have the required scopes. When considering
users who need to use the application and web services, you must ensure users have the required
access scopes. For ideas on how to manage access to applications and web services, go to Genero Identity Provider scenario. For more information on managing user scopes, refer to the IdP
documentation.