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.
About this task:In service-to-service –
also known as "machine-to-machine" – implementation, an application authenticates itself with GIP
using its Client ID and Client Secret. GIP 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 scopes for the service or APIs providing the service with the GIP using the
Console App.
You should already have defined scopes in your Genero web service source file
(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.
-
Generate the stub for your Genero web service (client).
You must have the web service (client) secured by the GIP 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 GIP 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://host:port/gas/ws/r/services/GeneroIdentityProvider
--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 GIP.
- The URL of the GIP 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 by GIP 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 GIP in the
IDP
element.
<APPLICATION Parent="ws.default" ...>
<EXECUTION>
</ENVIRONMENT_VARIABLE>
</PATH>
</MODULE>
<DELEGATE service="services/GeneroAccessService">
<IDP>https://host:port/gas/ws/r/services/GeneroIdentityProvider</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 secure your web service (server side) in a Genero Archive file using the Deployment
App.
You must package your applications and services into a Genero Archive for
deployment on the GAS. You create a Genero Archive (gar) with fglgar
gar. For more information about packaging a Genero Archive, refer to the Deploying
apps with Genero Archive pages in the Genero Application Server User Guide.
Your
gar
file must have a
MANIFEST file pointing to your web service configuration file
(
xcf).
The Deployment App secures the web service.
-
Generate the stub for your Genero web service (server side).
-
Get an access token from the GIP 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://host:port/gas/ws/r/services/GeneroIdentityProvider
--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 GIP.
- The URL of the GIP 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
-
Register the application with the GIP using the Console App.
For details about using the Console App's menu to register an application, go to
Manage applications
The Console App generates the CLIENT_PUBLIC_ID
and
CLIENT_SECRET_ID
that you use for requesting access tokens.
-
Configure your Genero web application xcf file for delegation.
Add the
DELEGATE
element and set its
service
attribute to
the Genero OpenIDConnectServiceProvider. Provide the URL of the GIP 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>https://host:port/gas/ws/r/services/GeneroIdentityProvider</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>
-
Deploy and secure your application with the GIP using the Deployment App.
Test your application by starting the GAS and entering the application URL in the browser. If
your browser is redirected to the GIP 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 GIP'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 as shown in the
step to Create your Genero REST 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 the web service, 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 GIP users, go to Manage groups.