Trouble with token auth via data source proxy

Hello!

TL;DR = when using the data source proxy, data doesn’t seem to be processed for {{ .SecureJsonData.someSecret }} style parameters. Is this intentional or a bug? Please read on…

I needed to implement my own token auth, since the tokenAuth feature of the data source proxy isn’t an exact fit for my needs for 2 reasons:

  1. My token auth service requires data be posted as application/json – but it appears Grafana only provides support for application/x-www-form-urlencoded. Is there a way to force it to post JSON instead?

  2. My token auth service requires an audience attribute instead of resource. In other words, I need to pass grant_type, client_id, client_secret, and audience. Is there a way to make this work?

Because of these reasons, I had to implement my own via fetch(). Here’s what’s in plugin routes:

{
  "path": "my_custom_token_auth",
  "url": "https://mydomain.com/oauth/token"
},

And here’s the request I’m passing to fetch():

{
method: ‘POST’,
url: this.instanceSettings.url + ‘/my_custom_token_auth’,
headers: {
‘Content-Type’: ‘application/json’, // this works, it does post JSON
‘Accept’: ‘/’,
},
data: {
grant_type: ‘client_credentials’,
client_id: ‘{{ .SecureJsonData.clientId }}’,
client_secret: ‘{{ .SecureJsonData.clientSecret }}’,
audience: ‘https://api.mydomain.com’, // here’s that custom audience thing I mentioned
},
}

When I pass an explicit clientId and clientSecret, it works perfectly. But as you see it above, with {{ .SecureJsonData.clientSecret }} inside data, that value isn’t getting substituted by the proxy.

I have a feeling I just need to build a backend plugin, but I’d rather not if there’s an alternative. Please let me know – thanks in advance!

BTW That header is correct and standard - RFC 6749 - The OAuth 2.0 Authorization Framework

Your OAuth server doesn’t follow specification, when it requires a json header for token request.

I think you should be able to use the request body property of route, see Add authentication for data source plugins | Grafana documentation

1 Like

Thank you @mefraimsson! That works exactly how I need it to. For posterity, here’s what worked…in plugin.json:

{
  "path": "my_custom_token_auth",
  "url": "https://mydomain.com/oauth/token",
  "headers": [
    {
      "name": "Content-Type",
      "content": "application/json"
    }
  ],
  "body": {
    "grant_type": "client_credentials",
    "client_id": "{{ .SecureJsonData.clientId }}",
    "client_secret": "{{ .SecureJsonData.clientSecret }}",
    "audience": "https://api.mydomain.com"
  }
},

And then in the datasource plugin:

const response = await lastValueFrom(getBackendSrv().fetch<OAuthTokenResponse>({
  method: 'POST',
  url: this.proxiedUrl('my_custom_token_auth'),
}));

Thanks again!

1 Like