Client credentials auth flow

This one had me thinking. REST API with Single Sign On - #10 by jadixon
To my knowledge, there’s no way to register a client application to get token having only clientId and secret. Yet the OP seems to have done so (albeit on-prem). Is there a way to register an app to enable OAuth client_credentials flow (no username pw needed) for cloud?

I didnt read the OP, so this may be irrelevant to your question.

You can use the TokenSvc to get a token, then pass that for Auth in lieu of basic auth.

Thanks for your reply. I understand that flow using username, password, apikey.

What I’d like to do is call TokenSvc with clientid, secret, apikey (no username, password)

This typaically requires app registraion up front, but I don’t know if any way to do that. Is it possible?

Ah, yeah, I dont know of a way.

You could get creative with an external solution. Handle the token generation yourself in an api (while still using user\pass)

This isn’t possible with native Epicor, you can do it with Epicor IDP or Azure but not native Epicor.

For what its worth ClientID + Secret is no different than Useranme + Password just a different name for the same thing.

There’s nothing stopping you from creating a
UserName: e7f30f83-252b-47bb-b7c5-7c6f7831d4f7
Password: %Ym+9r’hP;<h~*ouviG^~?w(2n&Lk@

Set the Integration Account Checkbox to True in User Maintenance and give the User a Scope. Et Voila, your very own Client / Secret equivalent

1 Like

Yeah. Trying to avoid standing up a static webapp just to secure un,pw from client. It’s quite likely Epicor is doing this to integrate w other services and epiIdp can likely do it. Just don’t see it documented anywhere. Like even if it takes a support case to register, that’d be fine. We need a way to do either auth_code flow with secret or client_credentials flow with secret.

Is it a specific program that you are trying to integrate with? (Externally?) If that’ the case you’ll have to go through a 3rd Party app

I suppose you’re right. and manually setting up un/pw is not unlike admin consent flow.

It just seems non-standard for no good reason - meanwhile the endpoint supports client/secret but we’ve no way to utilize it.

I have IDP + Azure and cannot find any docs on how to do an app reg auth flow into ERP APIs.

What makes you say this? I don’t believe Epicor native supports this. (Unless they added it recently)

Ah, the token service… Interesting!

those admin methods are SUper Admin only (cloud support)

You know… you aren’t gonna like what I found when I poked at it :zipper_mouth_face: Lets just say it doesn’t support… client flow and leave it at that

Oh No Facepalm GIF

3 Likes

What’s the user case, Josh?

Could Certificate Based Authentication work? I’ve wanted to try it here, but reasons.

TokenService only gets new internal tokens for currently logged in users. ClientId and secret there are not used and probably will never be because it was suggested to not continue with that implementation and use standard providers instead. That is Azure AD and IDP.

2 Likes

Hold on, there’s a treasure trove of articles in IdP help. I’m quite certain I’ve looked there before and not found much so perhaps these are new or perhaps I missed them.

Let me try some things and report back.

As far as use case, I’m experimenting. Trying to reduce some manangement/maintenace layers to the bare min, secure setup. I’m an Azure shop and we’ve (per-docs) granted basically the highest level of admin consent to get IdP to work. Now why am I still dealing w uns/pws, flow for custom apps?

Thanks for your help. Now I know not to bother w ERP/ICE token endpoints for this flow.

1 Like

besides Epicor help on IDP you can investigate the documentation for Azure AD- Entra and Duende Software, formerly IdendityServer

2 Likes

Update:

The docs are not quite right, but here’s a working postman sample collection:

Epicor IdP to ERP API - Client Credentials Flow

Prerequisites

  1. add new secret to ServerToServer client in IdP admin per article:
    Accessing Kinetic ERP REST using IdP
  2. retain client_id and secret
  3. Add and API Key in Kinetic API Key Maintenence

Postman example (API v2)

  1. Download and install Postman.

  2. Place the below code in a text editor:

{
  "info": {
    "_postman_id": "db3b5f93-7216-4029-bd71-44d83a5066aa",
    "name": "Epicor ERP API v2 + Epicor Identity",
    "description": "This collection contains the following examples:\r\n- How to get an access token for the Epicor ERP from Epicor Identity\r\n- How to use the access token to get a customer list using ODATA",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "_exporter_id": "252182"
  },
  "item": [
    {
      "name": "Get Epicor Identity Access token for Epicor ERP",
      "request": {
        "method": "POST",
        "header": [],
        "body": {
          "mode": "urlencoded",
          "urlencoded": [
            {
              "key": "grant_type",
              "value": "client_credentials",
              "type": "text"
            },
            {
              "key": "scope",
              "value": "epicor_erp idp_access",
              "type": "text"
            },
            {
              "key": "client_id",
              "value": "{{client_id}}",
              "type": "text"
            },
            {
              "key": "client_secret",
              "value": "{{client_secret}}",
              "type": "text"
            }
          ]
        },
        "url": {
          "raw": "{{idp_url}}/connect/token",
          "host": [
            "{{idp_url}}"
          ],
          "path": [
            "connect",
            "token"
          ]
        }
      },
      "response": []
    },
    {
      "name": "Get Customer List",
      "request": {
        "method": "GET",
        "header": [
          {
            "key": "Authorization",
            "value": "Bearer {{bearer_token}}",
            "type": "text"
          },
          {
            "key": "x-api-key",
            "value": "{{api_key}}",
            "type": "text"
          }
        ],
        "url": {
          "raw": "{{erp_url}}/api/v2/odata/{{company}}/Erp.BO.CustomerSvc/List",
          "host": [
            "{{erp_url}}"
          ],
          "path": [
            "api",
            "v2",
            "odata",
            "{{company}}",
            "Erp.BO.CustomerSvc",
            "List"
          ]
        }
      },
      "response": []
    }
  ],
  "auth": {
    "type": "oauth2",
    "oauth2": [
      {
        "key": "client_authentication",
        "value": "body",
        "type": "string"
      },
      {
        "key": "scope",
        "value": "epicor_erp",
        "type": "string"
      },
      {
        "key": "clientSecret",
        "value": "{{client_secret}}",
        "type": "string"
      },
      {
        "key": "clientId",
        "value": "{{client_id}}",
        "type": "string"
      },
      {
        "key": "accessTokenUrl",
        "value": "https://login.epicor.com/connect/token",
        "type": "string"
      },
      {
        "key": "refreshRequestParams",
        "value": [],
        "type": "any"
      },
      {
        "key": "tokenRequestParams",
        "value": [],
        "type": "any"
      },
      {
        "key": "authRequestParams",
        "value": [],
        "type": "any"
      },
      {
        "key": "tokenName",
        "value": "EpicId",
        "type": "string"
      },
      {
        "key": "challengeAlgorithm",
        "value": "S256",
        "type": "string"
      },
      {
        "key": "grant_type",
        "value": "client_credentials",
        "type": "string"
      },
      {
        "key": "addTokenTo",
        "value": "header",
        "type": "string"
      }
    ]
  },
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          ""
        ]
      }
    },
    {
      "listen": "test",
      "script": {
        "type": "text/javascript",
        "exec": [
          ""
        ]
      }
    }
  ],
  "variable": [
    {
      "key": "idp_url",
      "value": "https://login.epicor.com"
    },
    {
      "key": "erp_url",
      "value": ""
    },
    {
      "key": "client_id",
      "value": ""
    },
    {
      "key": "client_secret",
      "value": ""
    },
    {
      "key": "api_key",
      "value": ""
    },
    {
      "key": "company",
      "value": ""
    }
  ]
}
  1. Save the file, named for example, IdP-ERP-OAuth-Postman.json.
    Optionally: Edit the file to include your variable values listed in step 8 or wait to do it in postman.

  2. In Postman, from the File menu, select Import.

  3. Drag and drop or search for and select IdP-ERP-OAuth-Postman.json.

  4. In the left pane, verify Collections tab is selected.

  5. Right-click Epicor ERP API v2 + Epicor Identity collection and select Edit.

  6. Select the Variables tab and adjust values corresponding to your Epicor ERP environment.

Variable Value
idp_url https://login.epicor.com
erp_url (enter your ERP application URL)
client_id (enter your client ID)
client_secret (enter your client secret)
api_key (enter your API Key)
company (enter your company ID)

Test Postman requests:

  1. AUTHORIZE: Select the Top-level collection, Authorization header, click Get New Token
  2. TEST: Use the Get Customer List request to get an example on how to send the access token to get some data out of Kinetic using the Customer ODATA REST API. Customer request inherits Auth header from parent(collection)
  3. Optionally: Use the Get Epicor Identity Access token for Epicor ERP request to get an example on how to get an access token for Kinetic. For ERP API requests, under the Headers tab, add Authorization header having value “Bearer {{bearer_token}}” replace the value of variable {{bearer_token}} with the value you generate using Get Epicor Identity Access token for Kinetic request.
1 Like

The Excel sample didn’t work for me either for similar reasons, but here’s a fixed up one that does. Still no method to keep creds out of plain text, but dropped reliance on User Account Mainenance and got rid of annoying Excel auth issues anyway…

Microsoft Excel Example API v2 (Using Client and Secret)

  1. Launch Microsoft® Excel®.
  2. Click on Data > Get Data > From Other Sources > Blank Query.
  3. The Power Query Editor displays. Click the Advanced Editor found on the Home tab.
  4. Place the below code in the editor and replace the following variables with values corresponding to your Kinetic environment:
Variable Value
idp_base_url Enter "https://login.epicor.com"
client_id Enter your Inter-server client ID
client_secret Enter your Inter-server client secret
erp_api_base_url Enter Kinetic application URL in the form of ""https://centralusdtpilot7xx.epicorsaas.com/SaaSxxxxPilot"
erp_odata_get_url_part Enter OData parameter for the query, e.g. "/api/v2/odata/{{Company}}/Erp.BO.CustomerSvc/List"
api_key Enter API Key created in Kinetic (as described in the Prerequisites)

Replace the wildcards xxxxxx for the intended urls, company, etc for example:
"/api/v2/odata/EPIC06/Erp.BO.CustomerSvc/List"

let
    idp_base_url = "https://login.epicor.com",
    client_id = "",
    client_secret = "",
    erp_api_base_url = "https://xxxxxx.epicorsaas.com/xxxxxx",
    erp_odata_get_url_part = "/api/v2/odata/xxxxxx/Erp.BO.CustomerSvc/List",
    api_key = "",
    body = [
        grant_type = "client_credentials",
        scope = "epicor_erp",
        client_id = client_id,
        client_secret = client_secret
    ],
    result = Json.Document(
        Web.Contents(
            idp_base_url & "/connect/token",
            [
                Headers = [#"Content-Type" = "application/x-www-form-urlencoded"],
                Content = Text.ToBinary(Uri.BuildQueryString(body))
            ]
        )
    ),
    resultToken = result[access_token],
    erpResult = Json.Document(Web.Contents(erp_api_base_url,
    [
        Headers = [#"Authorization" = "Bearer " & resultToken, #"x-api-key" = api_key],
        RelativePath = erp_odata_get_url_part
    ]))[value],
    tabularValue = Table.FromList(erpResult, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
    expanded = Table.ExpandRecordColumn(tabularValue, "Column1", {"Company", "CustID", "Name", "CustNum"})
in
    expanded
  1. Click Done and then click Close & Load.

You can now use the contents of your Kinetic instance using the Kinetic Rest API v2.

If a Privacy Levels prompt pops up, check the box next to Ignore Privacy Levels… to continue, and select Save.

A security warning shows up when you share the newly created Excel file. Select Enable Content, followed by Yes

2 Likes