Regular Subscription
Introduction
PortOne API payment requests are signed to ensure their authenticity and integrity. This document provides guidelines on how to generate signature for a regular subscription request.
Steps
To generate a signature for a regular subscription request, follow these steps:
- Concatenate the required parameters of the request into a single string in alphabetical order.
- Calculate the SHA-256 hash of the resulting string.
- Base64-encode the hash to obtain the signature.
Code Examples
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
"net/url"
"strconv"
)
type RequestObj struct {
ClientKey string
Currency string
FailureUrl string
MerchantOrderRef string
Quantity int64
SuccessUrl string
}
func GenerateSignature(requestObj RequestObj, portOneSecret string) string {
// Create a url.Values map and add the necessary parameters
params := make(url.Values)
params.Add("client_key", requestObj.ClientKey)
params.Add("currency", requestObj.Currency)
params.Add("failure_url", requestObj.FailureUrl)
params.Add("merchant_order_ref", requestObj.MerchantOrderRef)
params.Add("quantity", strconv.Itoa(int(requestObj.Quantity)))
params.Add("success_url", requestObj.SuccessUrl)
// Encode the parameters
data := params.Encode()
// fmt.Println("data is:", data)
// Create the HMAC hash using SHA-256
secret := []byte(portOneSecret)
message := []byte(data)
hash := hmac.New(sha256.New, secret)
hash.Write(message)
// Convert the hash to a base64 string
hashValue := base64.StdEncoding.EncodeToString(hash.Sum(nil))
return hashValue
}
func main() {
portOneKey := "PORTONE_KEY"
portOneSecret := "PORTONE_SECRET"
// The unique merchant order reference generated by the merchant
merchantOrderRef := ""
requestObj := RequestObj{
ClientKey: portOneKey,
Currency: "USD",
MerchantOrderRef: merchantOrderRef,
Quantity: 1,
SuccessUrl: "https://subscription.portone.cloud/success.html",
FailureUrl: "https://subscription.portone.cloud/failure.html",
}
// Generate the signature
signature := GenerateSignature(requestObj, portOneSecret)
// Output the signature
fmt.Println("Signature is:", signature)
}
<?php
function GenerateSignature($requestObj, $secretKey) {
$data = array(
'client_key' => $requestObj->ClientKey,
'currency' => $requestObj->Currency,
'failure_url' => $requestObj->FailureUrl,
'merchant_order_ref' => $requestObj->MerchantOrderRef,
'quantity' => $requestObj->Quantity,
'success_url' => $requestObj->SuccessUrl
);
ksort($data);
$data = http_build_query($data);
$message = $data;
return base64_encode(hash_hmac('sha256', $message, $secretKey, true));
}
function main() {
$key = "PORTONE_KEY";
$secret_key = "PORTONE_SECRET";
// The unique merchant order reference generated by the merchant
$merchant_order_ref = "";
// Example request object
$requestObj = (object) [
'ClientKey' => $key,
'Currency' => 'USD',
'MerchantOrderRef' => $merchant_order_ref,
'Quantity' => 1,
'SuccessUrl' => 'https://subscription.portone.cloud/success.html',
'FailureUrl' => 'https://subscription.portone.cloud/failure.html'
];
$signature = GenerateSignature($requestObj, $secret_key);
echo "Signature: " . $signature;
}
main();
?>
const crypto = require('crypto');
const { URLSearchParams } = require('url');
function GenerateSignature(requestObj, secretKey) {
const params = new URLSearchParams();
params.append('client_key', requestObj.ClientKey);
params.append('currency', requestObj.Currency);
params.append('failure_url', requestObj.FailureUrl);
params.append('merchant_order_ref', requestObj.MerchantOrderRef);
params.append('quantity', requestObj.Quantity);
params.append('success_url', requestObj.SuccessUrl);
params.sort();
const message = params.toString();
const hashValue = crypto.createHmac('sha256', secretKey).update(message).digest('base64');
return hashValue;
}
const clientKey = 'PORTONE_KEY';
const secretKey = 'PORTONE_SECRET';
// The unique merchant order reference generated by the merchant
const merchantOrderRef = '';
const requestObj = {
ClientKey: clientKey,
Currency: 'USD',
FailureUrl: 'https://subscription.portone.cloud/failure.html',
MerchantOrderRef: merchantOrderRef,
Quantity: 1,
SuccessUrl: 'https://subscription.portone.cloud/success.html'
};
const signature = GenerateSignature(requestObj, secretKey);
console.log(`Signature: ${signature}\n`);
using System;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
namespace ConsoleApp
{
class PaymentRequest
{
public string ClientKey;
public string Currency;
public string FailureUrl;
public string MerchantOrderRef;
public int Quantity;
public string SuccessUrl;
}
class ApiSecurityExample
{
public static string GenerateSignature(PaymentRequest paymentRequest, string secret)
{
var map = new SortedDictionary<string, string>()
{
{ "client_key", paymentRequest.ClientKey },
{ "currency", paymentRequest.Currency },
{ "failure_url", paymentRequest.FailureUrl },
{ "merchant_order_ref", paymentRequest.MerchantOrderRef },
{ "success_url", paymentRequest.SuccessUrl },
{ "quantity", paymentRequest.Quantity.ToString() }
};
var stringBuilder = new StringBuilder();
foreach (var key in map.Keys)
{
if (stringBuilder.Length > 0)
{
stringBuilder.Append("&");
}
var value = map[key];
try
{
stringBuilder.Append((key != null ? Uri.EscapeDataString(key) : ""));
stringBuilder.Append("=");
stringBuilder.Append(value != null ? Uri.EscapeDataString(value) : "");
}
catch (ArgumentNullException e)
{
throw new Exception("The key or value is null.", e);
}
catch (UriFormatException e)
{
throw new Exception("Invalid format for key or value.", e);
}
}
var message = stringBuilder.ToString();
// Console.WriteLine("message: " + message);
var encoding = new ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(secret);
byte[] messageBytes = encoding.GetBytes(message);
var hmacsha256 = new HMACSHA256(keyByte);
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
string hash_value = Convert.ToBase64String(hashmessage);
return hash_value;
}
}
class Program
{
static void Main(string[] args)
{
string key = "PORTONE_KEY";
string secret = "PORTONE_SECRET";
// The unique merchant order reference generated by the merchant
string merchantOrderRef = "";
PaymentRequest paymentRequest = new PaymentRequest()
{
ClientKey = key,
Currency = "USD",
FailureUrl = "https://subscription.portone.cloud/failure.html",
MerchantOrderRef = merchantOrderRef,
SuccessUrl = "https://subscription.portone.cloud/success.html",
Quantity = 1
};
string signature = ApiSecurityExample.GenerateSignature(paymentRequest, secret);
Console.WriteLine("Signature: " + signature);
}
}
}
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.text.DecimalFormat;
import java.util.Map;
import java.util.TreeMap;
public class Main {
public static void main(String[] args) {
String key = "PORTONE_KEY";
String secret = "PORTONE_SECRET";
// The unique merchant order reference generated by the merchant
String merchantOrderRef = "";
String currency = "USD";
Integer quantity = 1;
// Create an instance of RequestObj using the default constructor
RequestObj requestObj = new RequestObj();
// Use setter methods to set the values
requestObj.setClientKey(key);
requestObj.setCurrency(currency);
requestObj.setMerchantOrderRef(merchantOrderRef);
requestObj.setSuccessUrl("https://subscription.portone.cloud/success.html");
requestObj.setFailureUrl("https://subscription.portone.cloud/failure.html");
requestObj.setQuantity(quantity);
String signature = generateSignature(requestObj, secret);
System.out.println("Signature: " + signature);
}
public static String generateSignature(RequestObj requestObj, String secretKey) {
try {
Map<String, String> params = new TreeMap<>();
params.put("client_key", requestObj.getClientKey());
params.put("currency", requestObj.getCurrency());
params.put("failure_url", requestObj.getFailureUrl());
params.put("merchant_order_ref", requestObj.getMerchantOrderRef());
params.put("success_url", requestObj.getSuccessUrl());
params.put("quantity", requestObj.getQuantity().toString());
// Encode the parameters
String data = encodeParams(params);
// System.out.println("data: " + data);
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
sha256_HMAC.init(secretKeySpec);
byte[] hash = sha256_HMAC.doFinal(data.getBytes());
return Base64.getEncoder().encodeToString(hash);
} catch (Exception e) {
throw new RuntimeException("Failed to calculate hmac-sha256", e);
}
}
public static String encodeParams(Map<String, String> params) {
StringBuilder encodedParams = new StringBuilder();
for (Map.Entry<String, String> entry : params.entrySet()) {
if (encodedParams.length() > 0) {
encodedParams.append("&");
}
encodedParams.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8))
.append("=")
.append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8));
}
return encodedParams.toString();
}
}
class RequestObj {
private String clientKey;
private String currency;
private String merchantOrderRef;
private String successUrl;
private String failureUrl;
private Integer quantity;
// Default constructor
public RequestObj() {
}
// Setter methods
public void setClientKey(String clientKey) {
this.clientKey = clientKey;
}
public void setCurrency(String currency) {
this.currency = currency;
}
public void setMerchantOrderRef(String merchantOrderRef) {
this.merchantOrderRef = merchantOrderRef;
}
public void setSuccessUrl(String successUrl) {
this.successUrl = successUrl;
}
public void setFailureUrl(String failureUrl) {
this.failureUrl = failureUrl;
}
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
// Getter methods
public String getClientKey() {
return clientKey;
}
public String getCurrency() {
return currency;
}
public String getMerchantOrderRef() {
return merchantOrderRef;
}
public String getSuccessUrl() {
return successUrl;
}
public String getFailureUrl() {
return failureUrl;
}
public Integer getQuantity() {
return quantity;
}
}
#!/usr/bin/python
# -*- coding: utf-8 -*-
import urllib.parse
import hashlib
import hmac
import base64
class RequestObj:
def __init__(self, ClientKey, Currency, FailureUrl, MerchantOrderRef, Quantity, SuccessUrl):
# Instance Variables
self.ClientKey = ClientKey
self.Currency = Currency
self.FailureUrl = FailureUrl
self.MerchantOrderRef = MerchantOrderRef
self.Quantity = Quantity
self.SuccessUrl = SuccessUrl
def GenerateSignature(requestObj, secretKey):
f = {
'client_key': requestObj.ClientKey,
'currency': requestObj.Currency,
'failure_url': requestObj.FailureUrl,
'merchant_order_ref': requestObj.MerchantOrderRef,
'success_url': requestObj.SuccessUrl,
'quantity': requestObj.Quantity
}
f = dict(sorted(f.items()))
message1 = urllib.parse.urlencode(f)
message = message1.encode('utf-8')
# print(f'message: {message}\n')
secret = secretKey.encode('utf-8')
signature = base64.b64encode(hmac.new(secret, message, digestmod=hashlib.sha256).digest()).decode('utf-8')
return signature
# Define constants
key = 'PORTONE_KEY'
secret = 'PORTONE_SECRET'
# The unique merchant order reference generated by the merchant
merchantOrderRef = ''
# Create an instance of RequestObj
requestObj = RequestObj(
ClientKey=key,
Currency='USD',
FailureUrl='https://subscription.portone.cloud/failure.html',
MerchantOrderRef=merchantOrderRef,
SuccessUrl='https://subscription.portone.cloud/success.html',
Quantity=1
)
# Call GenerateSignature
signature = GenerateSignature(requestObj, secret)
print(f'Signature: {signature}\n')
Parameter list to generate signature
client_key
client_key
string
The PortOne key of the merchant
currency
currency
string
The currency of the subscription
failure_url
failure_url
string
The URL to redirect to after a failed subscription
merchant_order_ref
merchant_order_ref
string
Order Reference sent by merchant to create the subscription
quantity
quantity
string
The quantity of the item being subscribed
success_url
success_url
string
The URL to redirect to after a successful subscription
Note
Refer to Subscription Request for the complete list of subscription request parameters.
Updated about 1 month ago