Help Center/ SparkRTC/ SDK Reference/ Access Authentication
Updated on 2023-11-14 GMT+08:00

Access Authentication

To ensure the communication security of SparkRTC, access authentication is required when a user joins a room. This chapter describes the implementation principles of SparkRTC access authentication and how to generate an authentication signature.

Authentication Principles

Huawei Cloud SparkRTC uses digital signatures for access authentication. You need to set signature and ctime when joining a room using the SDK. signature is generated by the tenant using app_key and app_id provided by SparkRTC and room_id, user_id, and ctime based on the signature generation example of SparkRTC. For details, see Table 1.
signature = hmacSha256(app_key,(app_id + room_id + user_id + ctime))
Table 1 Parameters

Parameter

Description

app_key

An authentication key is generated by SparkRTC for each app. The key must be securely stored.

For details about how to obtain app_key, see How Do I Obtain a Key?

app_id

Application ID generated by SparkRTC.

Obtain the value of app_id from Applications on the SparkRTC console.

room_id

ID of the room created by the tenant.

user_id

User ID used by the tenant to access SparkRTC.

ctime

Time when the signature authentication expires. The value is the current UTC time (UNIX timestamp) of the system plus the authentication expiration time (recommended: 2 hours; maximum: < 12 hours). The unit is second.

NOTE:

The value of ctime is the creation time plus the expiration time. For example, if the current time is 9:00 and the authentication expiration time is 30 minutes, the value of ctime is 9:30. That is, the signature becomes invalid after 9:30.

Tenants are advised to build their own app signature distribution servers to prevent the app_key from being leaked to the app. Figure 1 shows the authentication principles.

Figure 1 Authentication principles

Signature Generation Method

To generate a signature, perform the following steps:

  1. Combine app_id, room_id, user_id , and ctime into a string.
    1
    2
     long ctime = System.currentTimeMillis() / 1000 + 60 * 60;   // The validity period is 1 hour, in seconds.
    String content = app_id + "+" + room_id + "+" + user_id + "+" + ctime; 
    
  2. Use app_key to encrypt the string content in HMAC-SHA256 mode to obtain the signature string.
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
        String signatureStr = hmacSha(appKey, content, "HmacSHA256");
        static String hmacSha(String KEY, String VALUE, String SHA_TYPE) {
            try {
                SecretKeySpec signingKey = new SecretKeySpec(KEY.getBytes("UTF-8"), SHA_TYPE);
                Mac mac = Mac.getInstance(SHA_TYPE);
                mac.init(signingKey);
                byte[] rawHmac = mac.doFinal(VALUE.getBytes("UTF-8"));
    
                byte[] hexArray = {
                        (byte) '0', (byte) '1', (byte) '2', (byte) '3',
                        (byte) '4', (byte) '5', (byte) '6', (byte) '7',
                        (byte) '8', (byte) '9', (byte) 'a', (byte) 'b',
                        (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f'
                };
                byte[] hexChars = new byte[rawHmac.length * 2];
                for (int j = 0; j < rawHmac.length; j++) {
                    int v = rawHmac[j] & 0xFF;
                    hexChars[j * 2] = hexArray[v >>> 4];
                    hexChars[j * 2 + 1] = hexArray[v & 0x0F];
                }
                return new String(hexChars);
            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }
    

Signature Generation Example

To prevent the app_key from being leaked, you are advised to configure your own app signature distribution server. After app_id, room_id, user_id, and ctime are passed to the server, the server returns the signature. The following is sample code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
package com.xxx.xxx.utils;

import androidx.annotation.NonNull;

import com.alibaba.fastjson.JSON;
import com.huawei.rtcdemo.Constants;

import java.io.IOException;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import okhttp3.Response;

public class SignatureUtil {
    private static final String TAG = "SignatureUtil";

    public interface onSignatureSuccess {
        void onSuccess(String signature);
    }

    public static void getSignature(String appid, String roomid, String userid, long ctime, String signatureKey, onSignatureSuccess callback) {
        if (Constants.RTC_SIGNATURE_USE_LOCAL) {
            getSignatureLocal(appid, roomid, userid, ctime, signatureKey, callback);
        } else {
            getSignatureRemote(appid, roomid, userid, ctime, callback);
        }
    }

    private static void getSignatureLocal(String appid, String roomid, String userid, long ctime, String signatureKey, @NonNull onSignatureSuccess callback) {
        String content = appid + "+" + roomid + "+" + userid + "+" + ctime; // here "+" is real char in content.
        String signature = SignatureUtil.hmacSha256(signatureKey, content);
        callback.onSuccess(signature);
    }

    private static void getSignatureRemote(String appid, String roomid, String userid, long ctime, @NonNull onSignatureSuccess callback) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                HttpUtil httpUtil = new HttpUtil();
                // Constants.RTC_SIGNATURE_URL indicates the distribution server address with the user's application signature.
                String url = Constants.RTC_SIGNATURE_URL + "?appid=" + appid + "&roomid=" + roomid + "&userid=" + userid + "&ctime=" + ctime;
                Response response = httpUtil.sendGetMethodWithHead(url, "X-AUTH-TOKEN", Constants.RTC_AUTH_TOKEN);
                if (response == null) {
                    return;
                }

                if (response.isSuccessful()) {
                    try {
                        String json = response.body().string();
                        String signature = JSON.parseObject(json).getString("signature");
                        callback.onSuccess(signature);
                    } catch (IOException e) {
                        LogUtil.e(TAG, "getSignature failed:" + e.getMessage());
                    }
                } else {
                    LogUtil.e(TAG, "getSignature failed!");
                }
            }
        }).start();
    }

    public static String hmacSha256(String KEY, String VALUE) {
        return hmacSha(KEY, VALUE, "HmacSHA256");
    }

    private static String hmacSha(String KEY, String VALUE, String SHA_TYPE) {
        try {
            SecretKeySpec signingKey = new SecretKeySpec(KEY.getBytes("UTF-8"), SHA_TYPE);
            Mac mac = Mac.getInstance(SHA_TYPE);
            mac.init(signingKey);
            byte[] rawHmac = mac.doFinal(VALUE.getBytes("UTF-8"));

            byte[] hexArray = {
                    (byte) '0', (byte) '1', (byte) '2', (byte) '3',
                    (byte) '4', (byte) '5', (byte) '6', (byte) '7',
                    (byte) '8', (byte) '9', (byte) 'a', (byte) 'b',
                    (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f'
            };
            byte[] hexChars = new byte[rawHmac.length * 2];
            for (int j = 0; j < rawHmac.length; j++) {
                int v = rawHmac[j] & 0xFF;
                hexChars[j * 2] = hexArray[v >>> 4];
                hexChars[j * 2 + 1] = hexArray[v & 0x0F];
            }
            return new String(hexChars);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}