Skip to content

Tạo cặp khóa ​

Bahn yêu cầu hai cặp khóa P-256 (EC) cho mỗi merchant:

Cặp khóauseMục đích
Signing (Ký)sigBạn ký mỗi request body bằng private key của mình; Bahn xác minh bằng public key đã đăng ký của bạn.
Encryption (Mã hóa)encBahn mã hóa response bằng public key của bạn; bạn giải mã bằng private key của mình.

Hướng dẫn này tạo cả hai cặp khóa và ghi chúng vào các file JWK bằng Go và thư viện go-jose.


1. Thiết lập ​

Tạo một thư mục mới và cài đặt các dependency:

bash
mkdir keygen && cd keygen
go mod init keygen
go get github.com/go-jose/go-jose/v4
go get github.com/google/uuid

2. Tạo khóa ​

Tạo file main.go:

go
package main

import (
	"crypto/ecdsa"
	"crypto/elliptic"
	"crypto/rand"
	"encoding/json"
	"log"
	"os"

	"github.com/go-jose/go-jose/v4"
	"github.com/google/uuid"
)

func main() {
	// cặp khóa sig
	sigKID := uuid.NewString()
	sigPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		log.Fatalf("failed to generate sig key: %v", err)
	}

	// cặp khóa enc
	encKID := uuid.NewString()
	encPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
	if err != nil {
		log.Fatalf("failed to generate enc key: %v", err)
	}

	// JWKS riêng tư
	privSet := jose.JSONWebKeySet{
		Keys: []jose.JSONWebKey{
			{Key: sigPriv, KeyID: sigKID, Algorithm: string(jose.ES256), Use: "sig"},
			{Key: encPriv, KeyID: encKID, Algorithm: string(jose.ES256), Use: "enc"},
		},
	}

	// JWKS công khai
	sigPub := sigPriv.PublicKey
	encPub := encPriv.PublicKey
	pubSet := jose.JSONWebKeySet{
		Keys: []jose.JSONWebKey{
			{Key: &sigPub, KeyID: sigKID, Algorithm: string(jose.ES256), Use: "sig"},
			{Key: &encPub, KeyID: encKID, Algorithm: string(jose.ES256), Use: "enc"},
		},
	}

	privBytes, err := json.MarshalIndent(privSet, "", "  ")
	if err != nil {
		log.Fatalf("failed to marshal private jwks: %v", err)
	}
	pubBytes, err := json.MarshalIndent(pubSet, "", "  ")
	if err != nil {
		log.Fatalf("failed to marshal public jwks: %v", err)
	}

	if err := os.WriteFile("private_key.json", privBytes, 0600); err != nil {
		log.Fatalf("failed to write private_key.json: %v", err)
	}
	if err := os.WriteFile("public_key.json", pubBytes, 0644); err != nil {
		log.Fatalf("failed to write public_key.json: %v", err)
	}

	log.Printf("generated sig kid=%s, enc kid=%s", sigKID, encKID)
}

Chạy một lần:

bash
go run main.go
# generated sig kid=00b06c00-..., enc kid=acb9b4c7-...

3. Kết quả ​

Hai file được ghi vào thư mục hiện tại:

FileNội dungQuyền
private_key.jsonCả hai private key. Không bao giờ chia sẻ hoặc commit file này.0600
public_key.jsonCả hai public key. Gửi cho Bahn trong quá trình onboarding.0644

public_key.json

json
{
  "keys": [
    {
      "use": "sig",
      "kty": "EC",
      "kid": "00b06c00-3278-4f09-bf9b-6825cf889131",
      "crv": "P-256",
      "alg": "ES256",
      "x": "S1sGGCWsPQW8PDLKSZn1zOUzWH0GDGaHXFjeTphY5WA",
      "y": "pf74XAcJ33zwp_w1O57qJylhlej3mBvFOzwe29s6Jsg"
    },
    {
      "use": "enc",
      "kty": "EC",
      "kid": "acb9b4c7-aa0c-450b-9ebf-a0dc10a5d4b4",
      "crv": "P-256",
      "alg": "ES256",
      "x": "ge6PdsBMu9y9x_bvMg1g4K8CJ8j6xR_2_jyb0xYn5ss",
      "y": "rxE1YRebjiKyPHBRCbLrNHjTei42b2nasfOvhnvvk78"
    }
  ]
}

private_key.json

json
{
  "keys": [
    {
      "use": "sig",
      "kty": "EC",
      "kid": "00b06c00-3278-4f09-bf9b-6825cf889131",
      "crv": "P-256",
      "alg": "ES256",
      "x": "S1sGGCWsPQW8PDLKSZn1zOUzWH0GDGaHXFjeTphY5WA",
      "y": "pf74XAcJ33zwp_w1O57qJylhlej3mBvFOzwe29s6Jsg",
      "d": "h6s7t1LWWSb_-P2H25dZ_T-EyxCkZdDSVSg-BhXYKNs"
    },
    {
      "use": "enc",
      "kty": "EC",
      "kid": "acb9b4c7-aa0c-450b-9ebf-a0dc10a5d4b4",
      "crv": "P-256",
      "alg": "ES256",
      "x": "ge6PdsBMu9y9x_bvMg1g4K8CJ8j6xR_2_jyb0xYn5ss",
      "y": "rxE1YRebjiKyPHBRCbLrNHjTei42b2nasfOvhnvvk78",
      "d": "Uv_5PRnWdrtQQzv_nzowArZ3m2y7pbpeOrc7abkaqbk"
    }
  ]
}

Trường d là số vô hướng riêng tư (private scalar) — nó chỉ xuất hiện trong private_key.json và là thứ cho phép bạn ký và giải mã.

WARNING

private_key.json chứa vật liệu khóa nhạy cảm. Lưu trữ nó trong một secrets manager hoặc vault đã được mã hóa và thêm vào .gitignore. Không bao giờ chia sẻ nó với Bahn hoặc bất kỳ ai khác.


Bước tiếp theo ​

  • Gửi public_key.json cho Bahn và ghi lại cả hai giá trị kid — bạn sẽ sử dụng chúng trong mọi header JWS và JWE.
  • Tiếp tục với Thực hiện request đầu tiên để ký và gửi lệnh gọi API đầu tiên của bạn.

Developers