All Products
Search
Document Center

Application Real-Time Monitoring Service:Share Grafana dashboards with API key links

Last Updated:Mar 11, 2026

Managed Service for Grafana lets you generate shareable dashboard links that bypass Grafana authentication. Recipients view the dashboard directly -- no Grafana account required.

Authentication is handled by an API key (Grafana 9.0.x) or a service account token (Grafana 10.0.x and later) embedded in the URL. Compared to snapshots (which freeze data at a point in time) and anonymous mode (which requires IP whitelisting), API key links show live data with no IP restrictions.

Important

Anyone with the shareable URL can view the dashboard. Use the Viewer role for the API key or service account token to restrict access to read-only. For external sharing, use a signed URL (v2) to avoid exposing the raw key. See the "Generate a signed shareable link (v2)" section below.

How it works

  1. Enable API key sharing in the Grafana workspace parameters.

  2. Create an API key or service account token with Viewer permissions.

  3. Get the dashboard share link from the Grafana UI.

  4. Append the key or token to the URL as a query parameter.

Anyone with the resulting URL can view the dashboard without logging on.

Prerequisites

  • A Managed Service for Grafana workspace

  • Admin permissions in the Grafana workspace

  • Your Grafana version (9.0.x or 10.0.x), available on the Workspace Management page in the ARMS console

Enable API key sharing

  1. Log on to the ARMS console. In the left-side navigation pane, choose Managed Service for Grafana > Workspace Management.

  2. On the Workspace Management page, click the ID of the workspace that you want to manage.

  3. In the left-side navigation pane, click Parameter Settings.

  4. In the left-side parameter list, select aliyun, and then click Modify Parameters.

  5. Set api_key_share to true and click Save and Apply.

Configure iframe embedding (optional)

If you plan to embed the dashboard link in a web page using an <iframe> tag, configure additional parameters based on your scenario.

Cross-domain embedding (the link and the web page are on different domains):

Set the link to use HTTPS. Under the security section, set the following three parameters:

allow_embedding=true
cookie_samesite=none
cookie_secure=true
Cross-domain parameter configuration

Same-domain embedding (the link and the web page share the same domain):

Under the security section, set allow_embedding to true.

Embedding into another Grafana instance:

Under the panels section, set the following parameters:

enable_alpha = true
disable_sanitize_html = true

Create an API key or service account token

Choose the procedure that matches your Grafana version.

Note After an upgrade from 9.0.x to 10.0.x, existing API keys remain visible on the api keys page. Click migrate to service account to migrate them. After migration, the api keys page is hidden, but legacy keys continue to work.

Grafana 9.0.x

  1. Log on to the ARMS console. In the left-side navigation pane, choose Managed Service for Grafana > Workspace Management.

  2. On the Workspace Management page, find the workspace and click the URL in the URL column to open Grafana.

    Note Log on with the Grafana administrator account and the password you set when creating the workspace. Alternatively, click Sign in with Alibaba Cloud to log on with your Alibaba Cloud account.
  3. Click the Settings icon icon in the upper-left corner of the Grafana homepage.

  4. In the left-side navigation pane, choose Configuration > API Keys.

    Note Admin permissions are required to access the API Keys page.
  5. Click New API key or Add API key, and then configure the following parameters:

    ParameterDescription
    Key nameA unique name for the API key.
    RoleSelect Viewer.
    Time to liveThe validity period. Examples: 60s (60 seconds), 10m (10 minutes), 1d (one day).
  6. Click Add. In the dialog box that appears, copy and save the API key value.

    Important

    After you close this dialog box, the API key value is no longer accessible. Save it immediately.

    API Key value dialog

Grafana 10.0.x

  1. Log on to the ARMS console. In the left-side navigation pane, choose Managed Service for Grafana > Workspace Management.

  2. On the Workspace Management page, find the workspace and click the URL in the URL column to open Grafana.

    Note Log on with the Grafana administrator account and the password you set when creating the workspace. Alternatively, click Sign in with Alibaba Cloud to log on with your Alibaba Cloud account.
  3. Click the Settings icon icon in the upper-left corner of the Grafana homepage.

  4. In the left-side navigation pane, choose Management > Service Accounts.

    Important
    • - Admin permissions are required to access the Service Accounts page.

    • Creating a service account uses one of the available user account slots.

  5. Click Add service account token, configure the following parameters, and then click Create:

    ParameterDescription
    Display nameA unique name for the service account.
    RoleSelect Viewer.
  6. Click Add service account token and configure the following parameters:

    ParameterDescription
    Display nameA unique name for the token.
    ExpirationSelect No Expiration or Set Expiration date.
    Expiration dateIf you selected Set Expiration date, set the date.
  7. Click Generate token. In the dialog box that appears, click Copy to clipboard and close.

    Important

    After you close this dialog box, the token value is no longer accessible. Save it immediately.

Generate a shareable dashboard link

  1. In the Grafana UI, open the dashboard you want to share.

  2. Click the Share icon icon. In the dialog box that appears, click the Link tab and copy the shareable link.

    Grafana dashboard share link

  3. Append &aliyun_api_key=<API key value> to the end of the link. Replace <API key value> with the API key or service account token you saved earlier.

       https://grafana-example.grafana.aliyuncs.com/d/TZWea****/test?orgId=1&from=167081684****&to=167083844****&aliyun_api_key=eyJr****WkIwNnN2c0RTSD******
  4. Open the resulting URL to verify that the dashboard loads without requiring a Grafana login.

Generate a signed shareable link (v2)

The basic link from the previous section includes the raw API key in the URL. If the link is leaked, anyone can access the dashboard until the key expires or is deleted.

A signed link (v2) replaces the raw key with a time-limited MD5 signature. Each signed URL is valid for a configurable period (default: 3,600 seconds) and does not expose the original key.

Enable v2 mode

  1. Log on to the ARMS console. In the left-side navigation pane, choose Managed Service for Grafana > Workspace Management.

  2. On the Workspace Management page, click the workspace ID. In the left-side navigation pane, click Parameter Settings.

  3. Set api_key_share_version to v2 and click Save and Apply.

    api_key_share_version parameter set to v2

Build a signed URL

The signing process has three stages: extract the secret from the key, derive a PBKDF2 hash, and compute an MD5 signature with a timestamp. The steps differ slightly depending on whether you use an API key (Grafana 9.0.x) or a service account token (Grafana 10.0.x).

API keys (Grafana 9.0.x)

1. Base64-decode the API key

Decode the API key using Base64. The result is a JSON object containing k (secret), n (key name), and id (key ID).

Java

import java.util.Base64;

public class Base64Example {
    public static void main(String[] args) {
        String apiKey = "eyJr****REpzZGYzd2JIa0N3ekgyWjlWWmhrSTM5bWdGT2hGSmwiLCJuIjoidGVzdDEiLCJpZCI6MX0=";
        String decodeKey = new String(Base64.getDecoder().decode(apiKey));
        System.out.println(decodeKey);
    }
}

Output:

{"k":"DJsd****HkCwzH2Z9VZhkI39mgFOhFJl","n":"test1","id":1}

Go

package main

import (
    "encoding/base64"
    "fmt"
)

func main() {
    apiKey := "eyJr****REpzZGYzd2JIa0N3ekgyWjlWWmhrSTM5bWdGT2hGSmwiLCJuIjoidGVzdDEiLCJpZCI6MX0="
    decodeKey, err := base64.StdEncoding.DecodeString(apiKey)
    if err != nil {
        fmt.Println(err.Error())
        return
    }
    fmt.Println(string(decodeKey))
}

Output:

{"k":"DJsd****HkCwzH2Z9VZhkI39mgFOhFJl","n":"test1","id":1}

2. Derive a PBKDF2 hash

Use the decoded k value as the password and the n value (key name) as the salt.

ParameterValue
PasswordThe k value from the decoded JSON
SaltThe n value (API key name). Example: test1
Iterations10000
Output length50
Key size256
Output formatHex

Java

import javax.crypto.SecretKeyFactory;
import java.security.GeneralSecurityException;
import javax.crypto.spec.PBEKeySpec;
import java.security.spec.KeySpec;

public class PBKDFExample {
    public static void main(String[] args) {
        String password = "DJsd****HkCwzH2Z9VZhkI39mgFOhFJl";
        String salt = "test1";
        int iterationCount = 10000;
        int outputLength = 50 * 8;

        try {
            KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), iterationCount, outputLength);
            SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
            byte[] keyBytes = skf.generateSecret(spec).getEncoded();
            System.out.println(bytesToHex(keyBytes));
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
}

Output:

1e5b****80184e78832544aae4d2e031a3539c10b575b75d7c1d44af49fcf5a7de9c58a5f0035ce35fff0e5b0476e882****

Go

package main

import (
    "crypto/sha256"
    "encoding/hex"
    "fmt"

    "golang.org/x/crypto/pbkdf2"
)

func main() {
    password := "DJsd****HkCwzH2Z9VZhkI39mgFOhFJl"
    salt := "test1"
    newPasswd := pbkdf2.Key([]byte(password), []byte(salt), 10000, 50, sha256.New)
    encodePassword := hex.EncodeToString(newPasswd)
    fmt.Println(encodePassword)
}

Output:

1e5b****80184e78832544aae4d2e031a3539c10b575b75d7c1d44af49fcf5a7de9c58a5f0035ce35fff0e5b0476e882****

3. Compute the MD5 signature

Concatenate the PBKDF2 hash, an underscore, and the current Unix timestamp in seconds. Compute the MD5 hash of this string.

Format: <PBKDF2_hash>_<unix_timestamp>

Example input: 1e5b**<b data-pending="uicontrol" id="pending_db5ae8c0">80184e78832544aae4d2e031a3539c10b575b75d7c1d44af49fcf5a7de9c58a5f0035ce35fff0e5b0476e882</b>**_1726823533

Java

import java.security.MessageDigest;

public class MD5Example {
    public static void main(String[] args) {
        String pbkdfPassword = "1e5b****80184e78832544aae4d2e031a3539c10b575b75d7c1d44af49fcf5a7de9c58a5f0035ce35fff0e5b0476e882****";
        long timeSeconds = System.currentTimeMillis() / 1000;
        String key = pbkdfPassword + "_" + timeSeconds;
        System.out.println(getMD5String(key, "UTF-8"));
    }

    public static String getMD5String(String str, String charset) {
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
            messageDigest.reset();
            messageDigest.update(str.getBytes(charset));
            byte[] byteArray = messageDigest.digest();

            StringBuffer md5StrBuff = new StringBuffer();
            for (int i = 0; i < byteArray.length; i++) {
                if (Integer.toHexString(0xFF & byteArray[i]).length() == 1) {
                    md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i]));
                } else {
                    md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
                }
            }
            return md5StrBuff.toString().toLowerCase();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("MD5 error:" + e.getMessage());
        }
    }
}

Go

package main

import (
    "crypto/md5"
    "encoding/hex"
    "fmt"
    "io"
    "strconv"
    "time"
)

func main() {
    pbkdfPassword := "1e5b****80184e78832544aae4d2e031a3539c10b575b75d7c1d44af49fcf5a7de9c58a5f0035ce35fff0e5b0476e882****"
    timeSeconds := time.Now().Unix()
    key := pbkdfPassword + "_" + strconv.FormatInt(timeSeconds, 10)

    // Compute the MD5 hash
    hash := md5.New()
    io.WriteString(hash, key)
    md5Str := hash.Sum(nil)
    md5StrHex := hex.EncodeToString(md5Str)

    fmt.Println("MD5:", md5StrHex)
}

4. Build the signed URL

Append the following query parameters to the dashboard link:

ParameterDescriptionExample
aliyun_api_key_signThe MD5 signature. Changes with each generation.c3bf89b867cc88df72d507edc4d1****
aliyun_api_key_timestampThe Unix timestamp used in the signature. The link fails if this differs from the server time by more than 1 minute.1726823533
aliyun_api_key_nameThe API key name (the n value from the decoded JSON).test1
aliyun_api_key_org_idThe organization ID (the id value from the decoded JSON).1
aliyun_api_key_expire_secondsHow long the session remains valid after the initial load. Unit: seconds. Default: 3600.3600

Example signed URL:

https://grafana-example.grafana.aliyuncs.com/d/TZWea****/test?orgId=1&from=167081684****&to=167083844****&aliyun_api_key_sign=c3bf89b867cc88df72d507edc4d1****&aliyun_api_key_timestamp=1726823533&aliyun_api_key_name=test1&aliyun_api_key_org_id=1

By generating the signature programmatically on each request, you avoid exposing the raw API key and can rotate keys without breaking shared URLs.

Service account tokens (Grafana 10.0.x)

1. Split the token

Split the service account token by underscores into three parts: prefix, secret, and salt.

# Example token:
glsa_yV9HAOVCjNKkvKoLMiypOc5T0Oov****_4f5ff3ce

# After splitting:
Prefix:  glsa
Secret:  yV9HAOVCjNKkvKoLMiypOc5T0Oov****
Salt:    4f5ff3ce

2. Derive a PBKDF2 hash

Use the secret as the password and the salt (token suffix) as the PBKDF2 salt.

ParameterValue
PasswordThe secret portion of the token
SaltThe token suffix. Example: 4f5ff3ce
Iterations10000
Output length50
Key size256
Output formatHex

Java

import javax.crypto.SecretKeyFactory;
import java.security.GeneralSecurityException;
import javax.crypto.spec.PBEKeySpec;
import java.security.spec.KeySpec;

public class PBKDFExample {
    public static void main(String[] args) {
        String password = "yV9H****jNKkvKoLMiypOc5T0OovHXPV";
        String salt = "4f5ff3ce";
        int iterationCount = 10000;
        int outputLength = 50 * 8;

        try {
            KeySpec spec = new PBEKeySpec(password.toCharArray(), salt.getBytes(), iterationCount, outputLength);
            SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
            byte[] keyBytes = skf.generateSecret(spec).getEncoded();
            System.out.println(bytesToHex(keyBytes));
        } catch (GeneralSecurityException e) {
            e.printStackTrace();
        }
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }
}

Output:

c3cd****971bab928e4ecd6e7a00c74657696ea07d38c43f3bb5dc3190f2285cb80695cf7bf2f25c9b1f34fe1e0f9549****

Go

package main

import (
    "crypto/sha256"
    "encoding/hex"
    "fmt"

    "golang.org/x/crypto/pbkdf2"
)

func main() {
    password := "yV9H****jNKkvKoLMiypOc5T0OovHXPV"
    salt := "4f5ff3ce"
    newPasswd := pbkdf2.Key([]byte(password), []byte(salt), 10000, 50, sha256.New)
    encodePassword := hex.EncodeToString(newPasswd)
    fmt.Println(encodePassword)
}

Output:

c3cd****971bab928e4ecd6e7a00c74657696ea07d38c43f3bb5dc3190f2285cb80695cf7bf2f25c9b1f34fe1e0f9549****

3. Compute the MD5 signature

Same procedure as for API keys: concatenate the PBKDF2 hash, an underscore, and the current Unix timestamp in seconds, then compute the MD5 hash.

See the Java and Go examples in the "API keys (Grafana 9.0.x)" section, Step 3 above.

4. Build the signed URL

Append the following query parameters to the dashboard link:

ParameterDescriptionExample
aliyun_api_key_signThe MD5 signature.c3bf89b867cc88df72d507edc4d1****
aliyun_api_key_timestampThe Unix timestamp used in the signature. Expires if it differs from the server time by more than 1 minute.1726823533
aliyun_api_key_nameThe service account token name.sa-1-****<b data-pending="uicontrol" id="pending_bac6ccda">-</b>***<b data-pending="uicontrol" id="pending_4b5e594d">-75c7-41ae-94da-</b>*******
aliyun_api_key_org_idThe organization ID.1
aliyun_api_key_expire_secondsHow long the session remains valid after the initial load. Unit: seconds. Default: 3600.3600

Example signed URL:

https://grafana-example.grafana.aliyuncs.com/d/TZWea****/test?orgId=1&from=167081684****&to=167083844****&aliyun_api_key_sign=c3bf89b867cc88df72d507edc4d1****&aliyun_api_key_timestamp=1726823533&aliyun_api_key_name=test1&aliyun_api_key_org_id=1

Best practices

  • Rotate keys regularly. Change API keys or service account tokens every three months.

  • Use v2 signed links for external sharing. Signed links prevent raw key exposure and expire automatically.

  • Delete leaked keys immediately. If a key is compromised, delete it from the Grafana API Keys or Service Accounts page to revoke all links using that key.

  • Keep API keys under 100. The Grafana UI displays up to 100 keys at a time. Expired keys are retained but hidden by default.

  • Assign Viewer role only. Shared links should use the Viewer role to limit access to read-only dashboard viewing.

FAQ

The dashboard shows an error when accessed through an iframe

This typically means allow_embedding is not set to true. Go back to the "Enable API key sharing" section above and configure the iframe embedding parameters for your scenario.

iframe access error

The dashboard loads but shows no data

Dashboard displays no data

When embedding through an iframe, cookies may fail to write. Check the following:

  • Different domains: The link and the host page are on different domains. Set cookie_samesite to none and cookie_secure to true under security, and make sure the link uses HTTPS.

  • Mismatched cookie settings: cookie_samesite is none, but cookie_secure is false. Both must be configured together.

  • HTTP URL: The link uses HTTP instead of HTTPS. The cookie_secure parameter only works with HTTPS.

Reconfigure the parameters as described in the "Configure iframe embedding" section above.

The browser shows an error page when opening the shared link

Browser error page

Check the following:

  1. Update your browser to the latest version.

  2. Make sure cookies are enabled in your browser settings.

  3. In Chrome incognito mode, allow all cookies in the incognito settings.

Should I set a short or long validity period for the API key?

Base the validity period on your security requirements. Shorter periods are more secure but require more frequent rotation. For a balance between convenience and security, rotate keys every three months. If a key is leaked, delete it immediately to revoke access.

Is there a limit on the number of API keys?

No hard limit exists, but the Grafana UI only displays up to 100 keys at a time. Keep the total number at or below 100 for easier management.

Does the system delete expired API keys automatically?

No. Expired keys are hidden by default on the Grafana UI but remain stored. To view them, turn on Include expired keys. Delete expired keys manually to free up slots.

Show expired keys toggle