EPIC FHIR SMART 后端服务: { “error”: “invalid_client”, “error_description”: null }

huangapple go评论72阅读模式
英文:

EPIC FHIR SMART Backend Services: { "error": "invalid_client", "error_description": null }

问题

我正在尝试在Go编程语言中实现EPIC FHIR的SMART后端服务(后端OAuth 2.0)。我已经创建了我的开发帐户,在那里上传了公钥,并选择了backend system作为应用程序受众。

我相当确定我的JWT令牌是正确的。我在jwt.io上对其进行了检查,签名是正确的。然而,我总是得到以下错误:

{ "error": "invalid_client", "error_description": null }

我还尝试了其他可能的解决方案,例如:

  • 确保JWT声明中的过期日期在5分钟内
  • 将有效负载放置在具有正确内容类型的正文中,即application/x-www-form-urlencoded
  • 确保使用沙盒client_id
  • 使用正确的JWT签名方法(RS384

我应该怎么解决这个问题?

顺便说一句,我还看到了Google Groups上的几次讨论,说在创建开发帐户后等待一两天是值得的。

以下是我的代码。感谢帮助!

var (
	oauth2TokenUrl  = "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token"
	sandboxClientID = "..."
	privateKey      = "..."
)

// 加载私钥
signKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(privateKey))
So(err, ShouldBeNil)

// 构造JWT声明
now := time.Now()
claims := jwt.MapClaims{
	"iss": sandboxClientID,
	"sub": sandboxClientID,
	"aud": oauth2TokenUrl,
	"jti": uuid.New().String(),             // 填写参考ID
	"exp": now.Add(1 * time.Minute).Unix(), // 不能超过5分钟!
}
log.Info("  => claims:", utility.ToJsonString(claims))

// 使用RS384算法使用私钥生成签名令牌
alg := jwt.SigningMethodRS384
signedToken, err := jwt.NewWithClaims(alg, claims).SignedString(signKey)
So(err, ShouldBeNil)
log.Info("  => signed token", signedToken)

// 准备API调用负载
payload := map[string]string{
	"grant_type":            "client_credentials",
	"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
	"client_assertion":      signedToken,
}

// 发送API调用
req := resty.New().
	R().
	EnableTrace().
	SetFormData(payload)
res, err := req.Post(oauth2TokenUrl)
So(err, ShouldBeNil)
log.Info("  => response status:", res.StatusCode())
log.Info("  => response header:", res.Header())
log.Info("  => response body:", string(res.Body()))

// 解析响应
resBody := make(map[string]interface{})
err = json.Unmarshal(res.Body(), &resBody)
So(err, ShouldBeNil)
英文:

I'm trying to implement the EPIC FHIR SMART Backend Services (Backend OAuth 2.0)
on go programming language.

I've created my dev account, uploaded the public key there, and selecting the backend system as the application audience.

I'm pretty sure my jwt token is correct. I've inspected it on jwt.io, the signature is correct. However, I always get this error:

> { "error": "invalid_client", "error_description": null }

I've tried other possible solutions as well such as:

  • ensuring the expiration date within the jet claim is below 5 minutes
  • placing the payload in the body with the correct content type, which is application/x-www-form-urlencoded
  • ensuring to use the sandbox client_id
  • using the correct jwt sign in method (RS384)

What should I do to resolve this issue?

Btw, I also saw several discussions on the google groups saying that it's worth to wait for one or two days after the dev account is created.

Below is my code. Appreciate the help!

var (
	oauth2TokenUrl  = "https://fhir.epic.com/interconnect-fhir-oauth/oauth2/token"
	sandboxClientID = "..."
	privateKey      = "..."
)

// load private key
signKey, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(privateKey))
So(err, ShouldBeNil)

// construct jwt claims
now := time.Now()
claims := jwt.MapClaims{
	"iss": sandboxClientID,
	"sub": sandboxClientID,
	"aud": oauth2TokenUrl,
	"jti": uuid.New().String(),             // fill with reference id
	"exp": now.Add(1 * time.Minute).Unix(), // cannot be more than 5 minutes!
}
log.Info("  => claims:", utility.ToJsonString(claims))

// generate signed token using private key with RS384 algorithm
alg := jwt.SigningMethodRS384
signedToken, err := jwt.NewWithClaims(alg, claims).SignedString(signKey)
So(err, ShouldBeNil)
log.Info("  => signed token", signedToken)

// prepare api call payload
payload := map[string]string{
	"grant_type":            "client_credentials",
	"client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
	"client_assertion":      signedToken,
}

// dispatch the api call
req := resty.New().
	R().
	EnableTrace().
	SetFormData(payload)
res, err := req.Post(oauth2TokenUrl)
So(err, ShouldBeNil)
log.Info("  => response status:", res.StatusCode())
log.Info("  => response header:", res.Header())
log.Info("  => response body:", string(res.Body()))

// parse response
resBody := make(map[string]interface{})
err = json.Unmarshal(res.Body(), &resBody)
So(err, ShouldBeNil)


</details>


# 答案1
**得分**: 9

太棒了我现在明白了

解决方案就是**等待**这让我感到困惑因为我在文档中找不到任何关于这个的解释而且错误信息也不太友好

总结一下在创建开发应用程序并上传公钥之后我们需要等待几个小时/几天然后凭证最终将可用

等待部分适用于**开放史诗****应用市场**的开发者账户

<details>
<summary>英文:</summary>

Fantastic, I got it working now.

The solution is simply **waiting**! it was confusing because I can&#39;t find any explanation about this on the doc, and also the error message is not quite friendly.

in summary, after creating dev app and the public key is uploaded there, we have to wait for a few hours/days, and then the credentials will eventually be usable.

The waiting part is applied to both **open epic** and **app orchard** dev accounts.


</details>



# 答案2
**得分**: 4

似乎 Epic 游戏公司有一种每天运行一次的同步机制所以在创建账户后等待是唯一的解决办法请注意在应用程序设置中更改Endpoint URI您还需要等待一段时间

当将 `redirect_uri` 参数设置为类似 `localhost:3000` 的内容时也会出现错误 `{ "error": "invalid_client", "error_description": null }`

<details>
<summary>英文:</summary>

It seems that Epic has some kind of synchronising mechanism which runs once a day. So waiting after account create is the only solution. Please also note that, in app settings after `Endpoint URI` change you also have to wait some time.

Error `{ &quot;error&quot;: &quot;invalid_client&quot;, &quot;error_description&quot;: null }` also shows up when `redirect_uri` param is set to something like `localhost:3000`.

</details>



# 答案3
**得分**: 1

我也遇到了这个问题在我的情况下我在Epic SMART on FHIR应用程序的"应用受众"中选择了"患者"我能够在测试服务器上成功获取授权码但是当我尝试将其交换为访问令牌时我收到了"invalid_client"的错误消息

我犯的错误是**HTTP POST中的`redirect_uri`必须是一个绝对URL并且必须与您为应用程序指定的重定向URI匹配如果重定向URI无效生成的错误消息将显示"invalid client"这是误导性的)。**

以下是我使用的Python代码示例...

    data = {
        'grant_type': 'authorization_code',
        'code': request.GET.get('code'),
        'redirect_uri': 'http://127.0.0.1:8000/ehr_connection_complete/', # 这必须是一个绝对URL
        'client_id': '11111111-2222-3333-4444-555555555555',
    }
    response = post(url, data)

对于`redirect_uri`参数出现错误时生成"invalid_client"的错误消息我觉得有点奇怪但这在Epic的测试FHIR服务器上是正确的

希望这些信息对其他人有所帮助

<details>
<summary>英文:</summary>

I encountered this problem too. In my case, I was using &quot;Patients&quot; as the &quot;Application Audience&quot; selected for the Epic SMART on FHIR app. I was able to successfully obtain an authorization code on the test server, but when I attempted to exchange it for an access token I received &quot;invalid_client&quot; error message.

The mistake I made is that **the `redirect_uri` in the HTTP POST must be an absolute URL and must match a redirect URI you have specified for your app. If the redirect URI is invalid, the resulting error message will say &quot;invalid client&quot; (which is misleading).**

Here is a sample of the Python code I was using...

		data = {
			&#39;grant_type&#39;: &#39;authorization_code&#39;,
			&#39;code&#39;: request.GET.get(&#39;code&#39;),
			&#39;redirect_uri&#39;: &#39;http://127.0.0.1:8000/ehr_connection_complete/&#39;, # THIS MUST BE AN ABSOLUTE URL
			&#39;client_id&#39;: &#39;11111111-2222-3333-4444-555555555555&#39;,
		}
		response = post(url, data)

It felt odd to me that an error with the `redirect_uri` parameter generates an error message about `invalid_client`, but it&#39;s true with Epic&#39;s test FHIR server.

I hope this information helps others.

</details>



huangapple
  • 本文由 发表于 2021年9月10日 00:07:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/69121502.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定