Outbound OAuth

When ONE is acting as the Client App to a third party system, we refer to this as "outbound" OAuth. A ONE module (either created by ONE or by you) may need to make calls to an OAuth-enabled external service.

Using the following process, you can make the necessary OAuth-based authorization calls to get a token to call a service. For the purposes of this example, we will assume that your one instance is at https://myinstance.onenetwork.com and the service to be called is at https://mystorefrontservice.com.

  1. Register your One Network instance with the external service.

    The exact steps necessary to achieve this will vary service-to-service. But in general, you will manually get an account with the service, and then navigate to a developer's area where you can "register" your OAuth application. They will want some basic information from you such as application name, description, etc. Most importantly, they will likely want an "authorization callback URL". You should provide your base URL, e.g. https://myinstance.onenetwork.com.

    They will give you two critical pieces of information:

    • Client ID - This is a unique identifier for your application. This is considered 'public' information and does not have to be secured. (For example, it will appear in URLs given to users)

    • Client Secret - This is a unique identifier for your application which is known only by the service and by you. It should be secured. (For example should never appear in a URL given to a users)


  2. Load an OAuthOBClientApp into the database.

    Using load-data or some other standard Platform mechanism for loading models (like ModelDataService), create an OAuthOBClientApp record. You will need the client ID and secret provided earlier.
    images/download/attachments/144836134/oauth_load_ob_interface-version-1-modificationdate-1645137483000-api-v2.png

  3. Create a page that gives the user a URL to the authorization URL of the OAuth service.

    Let's assume that mystorefrontservice's documentation identifies the following authorization URL: https://mystorefrontservice.com/oauth/authorize

    Write a page in Platform that will redirect the user to this authorization page. For example, it might show a link that says "Click here to grant ONE access to mystorefrontservice.com to pull your store orders." We recommended you launch this URL in a new window.

    The "Click here" link should be generated using logic along the following lines:


    ModelDataService mds = Services.get(ModelDataService.class);
    OAuthOBService oauthService = Services.get(OAuthOBService.class);
     
    PlatformUserContext ctx = getPlatformUserContext();
     
    // Fetch the OAuthOBClientApp for the service, and using OAuthOBService, create an
    // OAuthOBTokenReq object, which will track the request process for creating the token.
    ModelQueryComponent filter = ModelQuery.sqlFilter("RESOURCE_SERVER_NAME = 'https://mystorefrontservice.com'");
    OAuthOBClientApp clientApp = mds.read(OAuthOBClientApp.class, ctx, null, filter).get(0);
    OAuthOBTokenReq tokenReq = oauthService.newAuthorizationRequest(clientApp, ctx);
     
    // We will develop this callback URL in the next step of the tutorial
    String callbackUrl = "https://myinstance.onentework.com/oms/rest/ZBKS/storefrontoauth/authorize";
     
    // OAuthClientRequest will help you formulate a URL to pass to mystorefrontservice.
    // It captures information including where to redirect to after authorization, what "scope"
    // we need access to (this value varies a lot per service), our OAuth client id, and other
    // information
    OAuthClientRequest request = OAuthClientRequest
    .authorizationLocation("https://mystorefrontservice.com/oauth/authorize")
    .setClientId(clientApp.getId())
    .setRedirectURI(callbackUrl)
    .setScope("storeorders:read")
    .setState(tokenReq.getClientState())
    .buildQueryMessage();
     
    return request.getLocationUri();



    This produces a URL which, when clicked by the user, will take them to a page in mystorefrontservice.com which will ask them to grant appropriate access, then redirect to myinstance.onenetwork.com.

  4. Create a callback URL REST Resource.

    After the user clicks the URL, mystorefrontservice.com will redirect back to the following URL, since that's what we specified as the callback in the previous step.

    https://myinstance.onentework.com/oms/rest/ZBKS/storefrontoauth/authorize

    When this redirect arrives, it will have all the remaining information we need to get the OAuth token so that we can start calling APIs.

    Create a REST Resource along the following lines to process this request.

    @Path("/storefrontoauth")
    public class OAuthOBResource extends BaseResource {
    private ModelDataService mds = Services.get(ModelDataService.class);
    private OAuthOBService oauthService = Services.get(OAuthOBService.class);
    private UserContextService ucService = Services.get(UserContextService.class);
    @GET
    @Path("/authorize")
    public String authorize() throws Exception {
    // This object captures the response, including the "client state" value we
    // sent them earlier.
    OAuthAuthzResponse resp = OAuthAuthzResponse.oauthCodeAuthzResponse(getRequest());
    String clientState = resp.getState();
    // Fetch the OAuthOBTokenReq we created when we generated the URL.
    PlatformUserContext ctx = getPlatformUserContext();
    OAuthOBTokenReq tokenReq = oauthService.readTokenReq(clientState, ctx);
    OAuthOBClientApp clientApp = mds.readById(OAuthOBClientApp.class, tokenReq.getSysOAuthOBClientAppId(), ctx);
    // Now we form a request to be issued to mystorefrontservice to get the actual
    // OAuth token we can use to call their APIs. We assume their documentation provided
    // https://mystorefrontservice.com/oauth/access_token as the URL for this.
    OAuthClientRequest request = OAuthClientRequest
    .tokenLocation("https://mystorefrontservice.com/oauth/access_token")
    .setGrantType(GrantType.AUTHORIZATION_CODE)
    .setClientId(clientApp.getId())
    .setClientSecret(clientApp.getSecret())
    .setCode(resp.getCode())
    .buildQueryMessage();
    request.setHeader("Accept", "application/json");
    // Execute the request to get the token
    OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
    OAuthAccessTokenResponse oAuthResponse = oAuthClient.accessToken(request, OAuthJSONAccessTokenResponse.class);
    // Now store the token
    OAuthOBToken token = oauthService.grantToken(oAuthResponse.getAccessToken(), tokenReq, vcCtx);
    return "Authorization Complete. Granted token: " + token.getToken();
    }
    }

  5. In this process, we take the incoming data to find the original OAuthOBTokenReq we created when the token was requested. Then we issue a "backchannel" (i.e. not through the browser) request from ONE to mystorefrontservice.com, sending the client secret and the token "code". The response to this request will have our token, which we store in the OAuthOBToken model.

    This completes the flow. At this point, we have a row in the OAuthOBToken model with a valid value in the Token field, and we can begin making calls to mystorefrontservice.com using that token. Often that is supported via a request parameter, for example:

    https://mystorefrontservice.com/api/getorders?token=98a1c5d4bbe0984da83c177ea1d94137d7e5d2a5