To carry out an unauthenticated request, 3 headers are required, X-Scope-Id
and X-Encrypted-Key
and X-Encrypted-User
.
X-Scope-Id
is the ID of the application's scope under which the user's account is being registered or authenticated. You can read more about Configuring your scope . Once you've set up your scope and have the ID you can simply past it in the request header here.
To setup an X-Encrypted-Key
you need to generate a random AES Key, and then RSA encrypt it with the secure enclaves public key, we'll use TypeScript for the example below.
Here we setup a cryptoObj
that can work in both browser and server environments and then a function to generate an AES Key.
Copy const cryptoObj = typeof window !== "undefined" ? window.crypto : crypto;
export const generateAesKey = async () => {
const cryptoKey = await cryptoObj.subtle.generateKey(
{
name: "AES-GCM",
length: 256,
},
true,
["encrypt", "decrypt"]
);
return await cryptoObj.subtle.exportKey("raw", cryptoKey);
};
Next we setup two function an encrypt
function, which we then use in our rsaEncrypt
function.
Copy const encrypt = async (algo, key, data) => {
try {
const encryptedResult = await cryptoObj.subtle.encrypt(algo, key, data);
return encryptedResult;
} catch (error) {
console.error("Encryption error:", error);
throw error;
}
};
const rsaEncrypt = async (
plainText: string,
encryptionKey: BufferSource,
keyFormat: "spki" = "spki",
hashName: "SHA-256" = "SHA-256"
) => {
if (!encryptionKey) {
throw Error("Encryption key not initialized");
}
const encoder = new TextEncoder();
const data = encoder.encode(plainText);
let cryptoKey: CryptoKey;
let encrypted: ArrayBuffer;
try {
cryptoKey = await importKey(
keyFormat,
encryptionKey,
{ name: "RSA-OAEP", hash: { name: hashName } },
["encrypt"]
);
encrypted = await encrypt({ name: "RSA-OAEP" }, cryptoKey, data);
return btoa(String.fromCharCode.apply(null, new Uint8Array(encrypted)));
} catch (error) {
console.error("RSA-OAEP Encryption error:", error);
throw error;
}
};
export const aesEncrypt = async (
plainText: string,
encryptionKey: BufferSource,
keyFormat: "raw" = "raw",
keyLength: number = 256
) => {
if (!encryptionKey) {
throw Error("Encryption key not initialized");
}
const encoder = new TextEncoder();
const data = encoder.encode(plainText);
let cryptoKey: CryptoKey;
let encrypted: ArrayBuffer;
try {
cryptoKey = await importKey(keyFormat, encryptionKey, { name: "AES-GCM", length: keyLength }, [
"encrypt",
]);
const iv = cryptoObj.getRandomValues(new Uint8Array(12)); // Initialization vector
encrypted = await encrypt({ name: "AES-GCM", iv }, cryptoKey, data);
const combined = new Uint8Array(iv.length + encrypted.byteLength);
combined.set(iv, 0);
combined.set(new Uint8Array(encrypted), iv.length);
return btoa(String.fromCharCode.apply(null, combined));
} catch (error) {
console.error("AES-GCM Encryption error:", error);
throw error;
}
};
With these function setup, we are able to generate our AES key, and then RSA Encrypt it using the public key of the secure enclave.
Copy const enclavePublicKey =
"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvQOa1gkatuN6KjaS4KEWsVZAN9i4Cf0j9jlmBW5RwCJ3Bxo32McP7axt4Ev6sMWM24lpCgXgu68S9KBYRcrcEB6dRcaupFGd+ER7M518fiJ0VtCZ+XRnmwn9fqEvotp9DPZOysJkUQ60kugCRKwNvfZzAFcDiubwiqsUY2sCm943a/u9Hym51SEetG+ZFPJZFOBqwRSGkOgGZ+9Ac7ITE+bWLCZk9DlzRu+BIoDOFzXZIn+/0a0X8BnLtRY4g50aew4J+4OllQagBbhYnPMvYExYIEUx6bdjQicw0Js6s2pHr+SFAX23kQtbVOVxb5+KEGp1d+6Q4Gx7FBoyWI5qPQIDAQAB";
const aesKey = await generateAesKey();
const aesKeyBytes = new Uint8Array(aesKey);
const aesKeyString = btoa(String.fromCharCode(...aesKeyBytes));
const encryptedAesKey = await rsaEncrypt(aesKeyString, enclavePublicKey);
const userDetails = {
username: "john_doe",
userDisplayName: "john_doe_crypto",
};
const encryptedUser = await aesEncrypt(JSON.stringify(userDetails), aesKey);
Now you have your encryptedAesKey
and encryptedUser
you can use this value as the value in the request header as X-Encrypted-Key
. With X-Scope-Id, X-Encrypted-User
and X-Encrypted-Key
setup, you can now start interacting with Passport API to register and authenticate users.
Last updated 10 months ago