Credentials & SDK Authentication Specification
Cryptographic specification for client public keys, server Ed25519 request signing, and SDK configuration.
https://taqlyn.com/shop/checkout?cartId=cart_9841&promo=WELCOME20&aff=partner_8Taqlyn enforces an asymmetric Ed25519 cryptographic security model. Traditional deep linking providers rely on shared opaque secret tokens (sk_live_...) hashed with bcrypt or SHA-256. If a developer accidentally bundles that shared secret into an iOS or Android app, attackers can decompile the binary and mint arbitrary links or hijack traffic.
Taqlyn solves this permanently:
- Client / Mobile apps receive only public identifiers (
client_id+public_key_id). They can resolve incoming links, but cannot forge signatures or perform mutating operations. - Server backends sign administrative and link creation requests using an Ed25519 private key (
PKCS#8 PEM). The private key is never stored by Taqlyn; incoming requests are validated against the stored public verifying key.
#Credential Roles Matrix
| Credential Component | Type | Format | Target Environment | Permitted Operations |
|---|---|---|---|---|
client_id | Public Identifier | app_test_<hex> / app_live_<hex> | Mobile SDKs & Server SDKs | App identification, edge routing lookup |
public_key_id | Public Key Handle | pk_test_<hex> / pk_live_<hex> | Mobile SDKs only | Link resolution (POST /v1/resolve), user in-app sharing |
private_key | Ed25519 Private Key | -----BEGIN PRIVATE KEY-----\n... | Server SDKs only | Creating short links (POST /v1/short-links), webhooks, admin APIs |
sk_* handle | Reference Token | sk_test_<hex> / sk_live_<hex> | Audit logs only | Tracking rotation history (cannot sign requests) |
#Client SDK Integration Matrix
Every client SDK requires clientId and publicKeyId. Both are safe to commit to source control or embed into client binaries.
#1. Android (Kotlin) — taqlyn-sdk
// In your android.app.Application class
import com.taqlyn.sdk.SdkCore
import com.taqlyn.sdk.SdkOptions
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
SdkCore.configure(
clientId = "app_live_8f92ab140cd3",
publicKeyId = "pk_live_a1b2c3d4e5f6",
options = SdkOptions(
env = "production", // "sandbox" or "production"
linkProcessingMode = SdkOptions.Mode.ALL // ALL, WEB_ONLY, or DEFERRED_ONLY
),
context = this
)
}
}- Permission Scope: Reads Google Play Install Referrer, catches App Links, and invokes
POST /v1/resolve. - Reference: Android Platform Guide
#2. iOS (Swift) — TaqlynSDK
// In your SwiftUI App declaration or AppDelegate
import SwiftUI
import TaqlynSDK
@main
struct MyApp: App {
init() {
SdkCore.configure(
clientId: "app_live_8f92ab140cd3",
publicKeyId: "pk_live_a1b2c3d4e5f6",
options: SdkOptions(env: .production)
)
}
var body: some Scene {
WindowGroup {
ContentView()
.onOpenURL { SdkCore.onOpenURL($0) }
.task {
// Resolve deferred links upon first install
_ = await SdkCore.resolveDeferred()
SdkCore.setReadyForNavigation(true)
}
}
}
}- Permission Scope: Reads pasteboard tokens (opt-in deferred), catches Universal Links, and invokes
POST /v1/resolve. - Reference: iOS Platform Guide
#3. React Native (TypeScript) — @taqlyn/sdk-react-native
import { configure, resolveDeferred, setReadyForNavigation } from '@taqlyn/sdk-react-native';
// Configure public credentials across iOS and Android engines
configure('app_live_8f92ab140cd3', 'pk_live_a1b2c3d4e5f6', {
env: 'production',
linkProcessingMode: 'all',
});
// Resolve upon initial app mount
export async function initializeTaqlyn() {
const link = await resolveDeferred();
if (link) {
console.log('Deferred deep link destination:', link.path, link.params);
}
setReadyForNavigation(true);
}- Reference: React Native Platform Guide
#4. Flutter (Dart) — taqlyn_sdk
import 'package:flutter/material.dart';
import 'package:taqlyn_sdk/taqlyn_sdk.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Taqlyn.configure(
clientId: 'app_live_8f92ab140cd3',
publicKeyId: 'pk_live_a1b2c3d4e5f6',
env: 'production',
);
runApp(const MyApp());
}- Reference: Flutter Platform Guide
#Server SDK Integration Matrix
Server SDKs sign HTTP requests with your Ed25519 Private Key. Configure them via environment variables on your backend.
#Standard Environment Variables
| Variable | Description |
|---|---|
TAQLYN_BASE_URL | Base API URL (e.g. https://api.rutvik.qzz.io or your custom domain). |
TAQLYN_CLIENT_ID | Application Client ID (app_test_* or app_live_*). |
TAQLYN_PRIVATE_KEY | PKCS#8 Ed25519 Private Key PEM (-----BEGIN PRIVATE KEY-----\n...). |
#1. Node.js / TypeScript (@taqlyn/sdk-node)
import { TaqlynClient } from "@taqlyn/sdk-node";
const client = new TaqlynClient({
baseUrl: process.env.TAQLYN_BASE_URL,
clientId: process.env.TAQLYN_CLIENT_ID!,
privateKey: process.env.TAQLYN_PRIVATE_KEY!,
});
const shortLink = await client.createShortLink({
destinationWeb: "https://example.com/products/headphones",
destinationPath: "/products/headphones",
params: { utm_source: "newsletter", promo: "VIP10" },
mode: "deferred_app",
trackUniqueUsers: true,
trackOpens: true,
});
console.log("Short URL:", shortLink.shortUrl);#2. Python (taqlyn-sdk)
import os
from taqlyn import TaqlynClient
client = TaqlynClient(
base_url=os.getenv("TAQLYN_BASE_URL", "https://api.rutvik.qzz.io"),
client_id=os.environ["TAQLYN_CLIENT_ID"],
private_key=os.environ["TAQLYN_PRIVATE_KEY"],
)
link = client.create_short_link(
destination_web="https://example.com/checkout",
destination_path="/checkout",
params={"coupon": "SPRING26"},
mode="deferred_app",
)
print("Minted link:", link.short_url)#3. Go (github.com/taqlyn/sdk-go)
package main
import (
"context"
"os"
"github.com/taqlyn/sdk-go"
)
func main() {
client, err := taqlyn.NewClient(taqlyn.Config{
BaseURL: os.Getenv("TAQLYN_BASE_URL"),
ClientID: os.Getenv("TAQLYN_CLIENT_ID"),
PrivateKey: os.Getenv("TAQLYN_PRIVATE_KEY"),
})
if err != nil {
panic(err)
}
link, err := client.CreateShortLink(context.Background(), taqlyn.CreateLinkInput{
DestinationWeb: "https://example.com/offer",
DestinationPath: "/offer",
Mode: "deferred_app",
})
println("Created link:", link.ShortURL)
}#4. Java / Kotlin JVM (com.taqlyn:sdk)
import com.taqlyn.sdk.TaqlynClient;
import com.taqlyn.sdk.model.CreateShortLinkRequest;
TaqlynClient client = TaqlynClient.builder()
.clientId(System.getenv("TAQLYN_CLIENT_ID"))
.privateKey(System.getenv("TAQLYN_PRIVATE_KEY"))
.build();
var link = client.createShortLink(CreateShortLinkRequest.builder()
.destinationWeb("https://example.com/deal")
.destinationPath("/deal")
.mode("deferred_app")
.build());#5. .NET / C# (Taqlyn.Sdk)
using Taqlyn;
var client = new TaqlynClient(new TaqlynOptions
{
ClientId = Environment.GetEnvironmentVariable("TAQLYN_CLIENT_ID")!,
PrivateKey = Environment.GetEnvironmentVariable("TAQLYN_PRIVATE_KEY")!,
});
var link = await client.CreateShortLinkAsync(new CreateShortLinkRequest
{
DestinationWeb = "https://example.com/promo",
DestinationPath = "/promo",
Mode = "deferred_app",
});#6. PHP (taqlyn/sdk-php)
use Taqlyn\TaqlynClient;
$client = new TaqlynClient([
'client_id' => getenv('TAQLYN_CLIENT_ID'),
'private_key' => getenv('TAQLYN_PRIVATE_KEY'),
]);
$link = $client->createShortLink([
'destination_web' => 'https://example.com/item',
'destination_path' => '/item',
'mode' => 'deferred_app',
]);#7. Ruby (taqlyn)
require 'taqlyn'
client = Taqlyn::Client.new(
client_id: ENV['TAQLYN_CLIENT_ID'],
private_key: ENV['TAQLYN_PRIVATE_KEY']
)
link = client.create_short_link(
destination_web: 'https://example.com/catalog',
destination_path: '/catalog',
mode: 'deferred_app'
)#Cryptographic Signed Request Protocol
If you are implementing a custom client or proxy, every request to privileged endpoints (POST/GET/PATCH/DELETE /v1/short-links) must provide three HTTP headers:
X-Taqlyn-Client-Id: app_live_8f92ab140cd3
X-Taqlyn-Timestamp: 1725537600
X-Taqlyn-Signature: 6e98b2c41804... (128-char hex string)#1. Canonical String Format
Construct the canonical message string as:
${timestamp}.${HTTP_METHOD}.${REQUEST_PATH}.${BODY_SHA256}timestamp: Exact Unix time in seconds (1725537600).HTTP_METHOD: Uppercase verb (POST,PATCH,DELETE).REQUEST_PATH: URL path without query parameters (/v1/short-links).BODY_SHA256: Hex-encoded SHA-256 digest of request body bytes. For empty bodies, use the hash of empty bytes (e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855).
#2. Signature Computation
Sign the UTF-8 bytes of the canonical string using your Ed25519 private key. Encode the resulting 64-byte signature as a lowercase hexadecimal string.
#3. Replay Protection Guard
The Taqlyn API gateway validates that: $$\left| \text{RequestTimestamp} - \text{ServerEpoch} \right| \le 300\text{ seconds}$$
Requests outside the ±300s skew window are rejected with credentials.timestamp_skew.
#Security Checklist
- Client binaries never hold private keys: Only
client_idandpublic_key_idare included in iOS, Android, React Native, and Flutter packages. - Private PEM stored in secrets managers: Store
TAQLYN_PRIVATE_KEYin AWS Secrets Manager, GCP Secret Manager, Vault, or Kubernetes Secrets. - Environment Isolation: Always use sandbox credentials in CI and development environments.
- Zero-Downtime Rotation: When rotating, roll backend servers first with the new PEM, then update mobile app releases.