Configure service to service type authentication with IdP

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.

Service-to-service – also known as "machine-to-machine" – implementation may vary depending on the IdP; refer to the IdP documentation for more information.

You must have packaged your applications and services into a Genero Archive. 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.

You will need your GAS running.

About this task:

The access token got from the Identity Provider (IdP) to check access to the service is also required to access the client service.

Steps

  1. 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.
    1. Register the web application.
    2. 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 SSO oauth2callback redirect URL
    The provider provides the CLIENT_PUBLIC_ID and CLIENT_SECRET_ID that you use for requesting access tokens to the protected resources.
  2. 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.
    Go to Import IdP metadata as OAuth2 for instructions on importing the metadata in the GAS. For details about the ImportOAuth tool, go to ImportOAuth.
    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.

  3. 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.
  4. Deploy and enable your application on the GAS using a Genero Archive file.
    Your gar file must have a MANIFEST file pointing to your application configuration file (.xcf).
    1. Deploy the gar file on the GAS.
      Use the gasadmin tool; for example, gasadmin gar --deploy-archive myAppGar.gar
    2. Enable the application on the GAS
      Use the gasadmin tool; for example, gasadmin gar --enable-archive myAppGar.gar
    For more details of deploying and managing applications and web services using Genero Archives on the GAS, go to the Deploying apps with Genero Archive page.

    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.

Web service

  1. On the IdP site, register the scopes for the service or APIs providing the service.
    Typically, it consists of the following tasks:
    1. Register the web service with the IdP.
    2. 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.

      For more information about WSScope and how it is implemented in a Genero REST web service, refer to the Handling security section and the WSScope topic in the Genero Business Development Language User Guide.

    3. 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 SSO oauth2callback redirect URL
  2. Configure your web service xcf file for delegation to the IdP.
    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.
  3. Deploy and enable your service on the GAS using a Genero Archive file.
    Your gar file must have a MANIFEST file pointing to your web service configuration file (.xcf).
    1. Deploy the gar file on the GAS.
      Use the gasadmin tool; for example, gasadmin gar --deploy-archive myServiceGar.gar
    2. Enable the service on the GAS
      Use the gasadmin tool; for example, gasadmin gar --enable-archive myServiceGar.gar
    For more details of deploying and managing applications and web services using Genero Archives on the GAS, go to the Deploying apps with Genero Archive page.
  4. Generate the stub for your 4GL client.
    1. Get an access token from the IdP to access the web service.

      Use the GetToken tool. For further information on using GetToken, go to GetToken.

      Line breaks have been added to the command example 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) that should be granted to the client for the service or services required in the token.

      You get an access token that is valid for 10 minutes. After ten minutes, you will need to query for a new access token.

    2. If your GAS is not running, start it.
      Test to ensure you can access the web service, by entering its URL in your browser, 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.
    3. Generate the stub.
      Use the fglrestful tool.
      For more details on using the fglrestful tool, refer to the fglrestful page in the Genero Business Development Language User Guide
      For example, from the web service URL (line breaks have been added to improve readability)
      fglrestful -o clientStub --oauth yes --tokenfile mytoken.json
          http://myhost:6394/gas/ws/r/myGroup/myXcf/myService?openapi.json
      Where:
      • clientStub specifies the filename of the stub in the output (-o) option.
      • --oauth yes specifies that the web service is secured by an IdP and code to handle OAuth access is generated in the stub.
      • --tokenfile specifies mytoken.json as the file where the token was saved in the previous step.
      • The URL of the web service is specified with the query string ?openapi.json to get the documentation file.

    The clientStub.4gl is generated from the OpenAPI document. It contains the code to manage calls made by client applications to the web service resources and from the web service to a client service, if that is also required by the service. You need to compile it and import the module into your Genero REST client application.

  5. Create your Genero REST client application.
    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:
    1. Import the stub file module.
    2. Import the OAuthAPI library.
    3. In the MAIN program block, code to retrieve the IdP IDs – provided via the GAS environment at runtime – and initiate OAuth.
      Important: Initiate OAuth first

      Call 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 clientStub
      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
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, as shown in the Create client application step.

    For more information on handling errors, refer to the Handle REST server errors page in Genero Business Development Language User Guide