All Products
Search
Document Center

Mobile Platform as a Service:Backend signature verification

Last Updated:Jun 04, 2026

Mobile Gateway Service signs each API request and sends the signature to your backend server, where you verify it to confirm the request came from the gateway and was not tampered with.

  • When you enable signature verification for an API group in the gateway console, Mobile Gateway Service signs each request in that group. You create the public and private keys used for signing in the gateway console.

  • Your backend server reads the signature from the request header, reconstructs the string to sign locally, applies the same algorithm, and compares the result against the received signature to determine whether the request is valid.

How it works

Verification has three stages:

  1. Read the headers. Mobile Gateway Service attaches the signature and key identifier to every request in two specific headers.

  2. Reconstruct the string to sign. Build the same string the gateway used as signing input: the HTTP method, the Content-MD5 value, and the constructed URL.

  3. Verify the signature. Apply your chosen algorithm (MD5+salt, RSA, SM3, or SM2) to the reconstructed string and compare the output to the received signature.

The gateway stores the computed signature in the request header X-Mgs-Proxy-Signature.

The secret key identifier — used to look up the corresponding secret value — is sent in the request header X-Mgs-Proxy-Signature-Secret-Key.

Construct the string to sign

Build the string to sign

String stringToSign =
HTTPMethod + "\n" +
Content-MD5 + "\n" +
Url
  • HTTPMethod: The HTTP method in uppercase, such as PUT or POST.

  • Content-MD5: The MD5 value of the request body, calculated as follows:

    1. If HTTPMethod is not PUT or POST, the MD5 value is an empty string ("").

    2. If the request body is a form, the MD5 is an empty string "". Otherwise, proceed to the next step.

    3. Calculate the MD5 value. If the request has no body, bodyStream is the string "null".

      String content-MD5 = Base64.encodeBase64(MD5(bodyStream.getBytes("UTF-8")));
      Important

      Even if the Content-MD5 value is an empty string (""), the subsequent line feed (\n) in the string to sign must be included. This results in two consecutive \n characters in the string.

  • Url: Constructed from the path, query, and form parameters. For example, given the request http://ip:port/test/testSign?c=3&a=1 with form parameters b=2&d=4, build the Url as follows:

    1. Extract the path — the portion after ip:port and before ?. In this example, the path is /test/testSign.

    2. If the request has no query or form parameters, the Url equals the path.

    3. Sort the query and form parameters by key in lexicographic order, then concatenate them as Key1=Value1&Key2=Value2&...&KeyN=ValueN. In this example, the result is a=1&b=2&c=3&d=4.

      Note

      If a query or form parameter has multiple values, use only the first value.

    4. Construct the Url in the format Path?Key1=Value1&Key2=Value2&...&KeyN=ValueN. In this example, the Url is /test/testSign?a=1&b=2&c=3&d=4.

Verify the signature

Use the same algorithm configured when you set up the API group in the gateway console.

  • Verify the signature using the MD5 algorithm

      String sign = "xxxxxxx"; // The signature from Mobile Gateway Service
      String salt ="xxx";     // The MD5 salt
    
      MessageDigest digest = MessageDigest.getInstance("MD5");
      String toSignedContent = stringToSign + salt;
      byte[] content = digest.digest(toSignedContent.getBytes("UTF-8"));
      String computedSign = new String(Hex.encodeHexString(content));
    
      boolean isSignLegal = sign.equals(computedSign) ? true : false;
  • Verify the signature using the RSA algorithm

      String sign = "xxxxxxx"; // The signature from Mobile Gateway Service
      String publicKey ="xxx"; // The RSA public key from Mobile Gateway Service
    
      PublicKey pubKey = KeyReader.getPublicKeyFromX509("RSA", new ByteArrayInputStream(publicKey.getBytes()));
      java.security.Signature signature = java.security.Signature.getInstance("SHA1WithRSA");
      signature.initVerify(pubKey);
      signature.update(stringToSign.getBytes("UTF-8"));
    
      boolean isSignLegal = signature.verify(Base64.decodeBase64(sign.getBytes("UTF-8")));
  • Verify the signature using a Chinese cryptographic algorithm

    SM3 algorithm:

     String sign = xxxx;
     String salt = xxxxxx;
     String toSignedContent = stringToSign + salt;
     byte[] srcData = toSignedContent.getBytes("UTF-8");
     SM3Digest digest = new SM3Digest();
     digest.update(srcData, 0, srcData.length);
     byte[] resultHash = new byte[digest.getDigestSize()];
     digest.doFinal(resultHash, 0);
     String computedSign = Hex.encodeHexString(resultHash);
     boolean isSignLegal  = sign.equals(computedSign);

    SM2 algorithm:

    String sign = xxxx;
    String pubKey = xxxx;
    
     Signature signature = Signature.getInstance("SM3withSM2", "LOCCSBC");
     KeyPair keyPair = getSmKeyPair(pubKey);
    
     PublicKey publicKey = keyPair.getPublic();
     signature.initVerify(publicKey);
     signature.update(stringToSign.getBytes("UTF-8"));
     return signature.verify(Hex.decodeHex(sign));
    public static KeyPair getSmKeyPair(String keyPairContent) throws IOException, InvalidKeySpecException, NoSuchProviderException, NoSuchAlgorithmException {
      KeyFactory keyFactory = KeyFactory.getInstance("SM2", "LOCCSBC");
    
      byte[] keyBytes = getPKCS1fromPEMString(keyPairContent);
      SM2ParameterSpec spec = SM2NamedCurveTable.getParameterSpec("sm2p256v1", "1234567812345678");
    
      SM2PrivateKeySpec sm2PrivateKeySpec = new SM2PrivateKeySpec(BigIntegers.fromUnsignedByteArray(keyBytes), spec);
      SM2PrivateKey prvkey = (SM2PrivateKey) keyFactory.generatePrivate(sm2PrivateKeySpec);
    
      SM2PublicKeySpec sm2PublicKeySpec = new SM2PublicKeySpec(prvkey.getQ(), spec);
      SM2PublicKey pubKey = (SM2PublicKey) keyFactory.generatePublic(sm2PublicKeySpec);
    
      return new KeyPair(pubKey, prvkey);
     }
    public static byte[] getPKCS1fromPEMString(String pemStr) {
      // pkcs1
      try {
       PEMParser reader = new PEMParser(new StringReader(pemStr));
       PemObject pemObject = reader.readPemObject();
       reader.close();
    
       ASN1InputStream asn1In = new ASN1InputStream(pemObject.getContent());
       ASN1Sequence derSequence = (ASN1Sequence) asn1In.readObject();
       asn1In.close();
    
       // openssl format
       Object obj = derSequence.getObjectAt(1);
       if (obj instanceof ASN1OctetString){
        return ((ASN1OctetString) obj).getOctets();
       }
    
       // gmssl format
       DEROctetString derOctetString = (DEROctetString)derSequence.getObjectAt(2);
       ASN1Sequence sequence = (ASN1Sequence)ASN1Sequence.fromByteArray(derOctetString.getOctets());
       return ((ASN1OctetString)sequence.getObjectAt(1)).getOctets();
      } catch (Exception e) {
       throw new RuntimeException(e);
      }
     }

Code examples

For a complete implementation, see HttpSignUtil.java.

Troubleshooting

Signature mismatch

If verification fails, the most common cause is a mismatch between the string to sign your backend constructed and the string the gateway used.

Log the exact value of stringToSign your backend constructs and compare it character by character against what the gateway computed. Check for:

  • Trailing \n after an empty Content-MD5. Even when Content-MD5 is an empty string, the \n separator must still be present in the string to sign. This produces two consecutive \n characters — a common source of mismatch.

  • Parameter sort order. Query and form parameters must be sorted in lexicographic order by key before concatenation. Confirm your sort is case-sensitive and matches the gateway's ordering.

  • Form body treated as content. If the request body is a form, Content-MD5 must be an empty string (""), not the MD5 of the form body bytes.

  • Wrong secret value. Confirm the salt or public key your backend uses matches the value configured in the gateway console for the secret key identifier in X-Mgs-Proxy-Signature-Secret-Key.