How to call Grafana API from Grafana datasource backend plugin

Hi,

I need to get the current user’s teams, unfortunately the User struct from GO SDK does not contain the field. I would like to do it by calling api/user in Grafana API from backend Datasource plugin.

Grafana version: 10.4.0
grafana-plugin-sdk-go v0.240.0

I am able to call the Grafana API from frontend:

getBackendSrv().fetch({
            url: `/api/user/teams`,
            method: 'GET',
        });

This request contains cookies: grafana_session and grafana_session_expiry.

However, I am facing issues by trying to do it using backend part. Please refer to the draft code:

func (d *Datasource) CheckHealth(ctx context.Context, req *backend.CheckHealthRequest) (*backend.CheckHealthResult, error) {
	settings := req.PluginContext.DataSourceInstanceSettings
	apiKey := settings.DecryptedSecureJSONData["apiKey"] // apiKey := "api-key"
	idToken := req.GetHTTPHeader(backend.OAuthIdentityIDTokenHeaderName) // idToken := ""
	token := strings.Fields(req.GetHTTPHeader(backend.OAuthIdentityTokenHeaderName)) // token := nil
	cookies := req.GetHTTPHeader(backend.CookiesHeaderName) // cookies := ""

	ctxLogger := log.DefaultLogger.FromContext(ctx)

	role := req.PluginContext.User.Role // role := "admin"

	appURL, err := req.PluginContext.GrafanaConfig.AppURL()
	if err != nil {
		return newHealthCheckErrorf("cannot get app URL %s", err.Error()), nil
	}

	idRequest, err := http.NewRequestWithContext(ctx, http.MethodGet, appURL+"api/user", nil)
	if err != nil {
		return newHealthCheckErrorf("cannot make request %s", err.Error()), nil
	}

	cfg := backend.GrafanaConfigFromContext(ctx)
	secret, err := cfg.PluginAppClientSecret()
	if err != nil {
		return newHealthCheckErrorf("cannot make secret %s", err.Error()), nil  // it fails here
	}


	clientOptions, err := req.PluginContext.AppInstanceSettings.HTTPClientOptions(ctx)
	if err != nil {
	 	return newHealthCheckErrorf("cannot make clientOptions %s", err.Error()), nil
	}

	idResp, err := d.httpClient.Do(idRequest)
	if err != nil {
		return newHealthCheckErrorf("cannot make request %s", err.Error()), nil // it returns 401
	}

	return &backend.CheckHealthResult{
		Status:  backend.HealthStatusOk,
		Message: "Data source is working",
	}, nil
}

HI.

The way you are trying to access the API is not possible because you need a way to authorize your plugin to call the API.

Take a look at the example of an app with service account grafana-plugin-examples/examples/app-with-service-account at main · grafana/grafana-plugin-examples · GitHub which can give you an insight of how to do it.

Thank you for your response.

I have added the externalServiceAccounts to my docker compose + added IAM section as in the above example. Now I am able to call API.

However, when I try to get the current user email (req.PluginContext.User.Email) and to cal users endpoint with filtering by email (fmt.Sprintf("api/users?email=%s", requestUserEmail))
I am receiving: 404 “{\n "message": "Not found"\n}\n”
-it calls “/api/users?email=admin@localhost”

I would appreciate next advices.

Hi.

The users API only works with basic auth so you won’t be able to retrieve it from your plugin using a service account token.