Created
March 5, 2025 22:43
-
-
Save adophilus/5f3cd676e7c7aeadad6d75a70a05bf70 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// This is the class for the `AccessToken`. The main purpose is to take in the claims and call the `toJwt` method to create a JWT. | |
var AccessToken = class { | |
apiKey; | |
roomId; | |
role; | |
/** | |
* Permissions for the token | |
*/ | |
permissions; | |
/** | |
* Token Options object | |
* | |
* - `ttl`: Time to live for the token or expiration time. can be a number of seconds or a string describing a time span zeit/ms | |
* @example 6 * 60 * 60, "2 days", "10h", "7d"` | |
* @default 4h | |
* | |
* - `maxPeersAllowed`: Maximum number of peers allowed in the room (Optional) | |
*/ | |
options = { | |
ttl: "4h" | |
}; | |
/** | |
* custom app data for the peer | |
*/ | |
metadata; | |
constructor(data) { | |
if (typeof document !== "undefined") { | |
logger.error( | |
"You should not include your API secret in your web client bundle.\n\nYour web client should request a token from your backend server which should then use " | |
); | |
} | |
if (!data.apiKey) { | |
throw new Error("api-key required"); | |
} | |
if (!data.roomId) { | |
throw new Error("roomId required"); | |
} | |
if (data.options?.metadata && estimateSize(data.options?.metadata) > MAX_METADATA_SIZE) { | |
throw new Error("Metadata size exceeds the limit of 5kb"); | |
} | |
this.apiKey = data.apiKey; | |
this.roomId = data.roomId; | |
this.metadata = data.options?.metadata; | |
if (data.options?.ttl) this.options.ttl = data.options?.ttl; | |
if (data.options?.maxPeersAllowed !== void 0) { | |
if (typeof data.options.maxPeersAllowed !== "number" || data.options.maxPeersAllowed <= 0) { | |
throw new Error("maxPeersAllowed must be a positive number"); | |
} | |
} | |
if (data.options?.maxPeersAllowed) { | |
this.options.maxPeersAllowed = data.options?.maxPeersAllowed; | |
} | |
if ("role" in data) { | |
if (isDefaultRole(data.role) && !("permissions" in data)) { | |
this.role = data.role; | |
this.permissions = ROLE_PERMISSIONS[data.role]; | |
} else if (isDefaultRole(data.role) && "permissions" in data) { | |
this.role = data.role; | |
this.permissions = { | |
...ROLE_PERMISSIONS[data.role], | |
...data.permissions | |
}; | |
} else if (typeof data.role === "string" && "permissions" in data) { | |
if (data.role.length > 20) { | |
throw new Error(`Custom role exceeds the limit of ${20} characters.`); | |
} | |
this.role = data.role; | |
this.permissions = { | |
...DEFAULT_PERMISSIONS, | |
...data.permissions | |
}; | |
} else { | |
throw new Error( | |
`Permissions must be provided for custom role: ${data.role}.` | |
); | |
} | |
} else if ("permissions" in data) { | |
this.permissions = { | |
...DEFAULT_PERMISSIONS, | |
...data.permissions | |
}; | |
} else { | |
throw new Error("Either a role or permissions must be provided."); | |
} | |
} | |
set updatePermissions(permissions) { | |
this.permissions = permissions; | |
} | |
set updateMetaData(data) { | |
if (data && estimateSize(data) > MAX_METADATA_SIZE) { | |
throw new Error("Metadata size exceeds the limit of 5kb"); | |
} | |
this.metadata = data; | |
} | |
/** | |
* Generate a JWT token | |
* @returns JWT token | |
* @example | |
* ```typescript | |
* const accessToken = new AccessToken({...}) | |
* accessToken.toJwt() | |
* ``` | |
*/ | |
async toJwt() { | |
const payload = { | |
roomId: this.roomId, | |
permissions: this.permissions, | |
role: this.role, | |
metadata: JSON.stringify(this.metadata) | |
}; | |
console.log(payload) | |
if (this.options?.maxPeersAllowed) { | |
payload.options = { | |
maxPeersAllowed: this.options.maxPeersAllowed | |
}; | |
} | |
const resp = await fetch(`${INFRA_URL}/api/v2/sdk/create-peer-token`, { | |
method: "POST", | |
body: JSON.stringify(payload), | |
headers: { | |
"Content-Type": "application/json", | |
"x-api-key": this.apiKey, | |
"Cache-Control": "no-store, max-age=0", | |
Pragma: "no-cache", | |
"x-sdk-version": SDK_VERSION | |
} | |
}); | |
if (resp.status === 401) { | |
throw new Error("API key missing or invalid"); | |
} | |
if (resp.status === 404) { | |
throw new Error("Room not found to be associated with the given API key"); | |
} | |
const { token } = await resp.json(); | |
return token; | |
} | |
}; | |
// Here's a sample code of what's generated | |
const accessToken = new AccessToken({ | |
apiKey, | |
roomId, | |
//available roles: Role.HOST, Role.CO_HOST, Role.SPEAKER, Role.LISTENER, Role.GUEST - depending on the privileges you want to give to the user | |
role: Role.SPEAKER, | |
//custom permissions give you more flexibility in terms of the user privileges than a pre-defined role | |
permissions: { | |
// admin: true, | |
canConsume: true, | |
canProduce: true, | |
canProduceSources: { | |
cam: true, | |
mic: true, | |
screen: true, | |
}, | |
canRecvData: true, | |
canSendData: true, | |
canUpdateMetadata: true, | |
}, | |
options: { | |
// metadata: { | |
// // you can add any custom attributes here which you want to associate with the user | |
// walletAddress: "mizanxali.eth" | |
// }, | |
}, | |
}); | |
// Here's the generated JWT | |
// eyJhbGciOiJSUzI1NiJ9.eyJwZWVySWQiOiJwZWVySWQtRXl1TGY5YzZ2Z0xZZ1huVTNrMUFpIiwicHVycG9zZSI6IlNESyIsInJvb21JbmZvIjp7InJvb21UeXBlIjoiVklERU8iLCJyb29tTG9ja2VkIjp0cnVlLCJtdXRlT25FbnRyeSI6ZmFsc2UsInZpZGVvT25FbnRyeSI6ZmFsc2V9LCJyb29tSWQiOiJ5dGstcWR4dS1xZWsiLCJtdXRlT25FbnRyeSI6ZmFsc2UsInZpZGVvT25FbnRyeSI6ZmFsc2UsInJvb21UeXBlIjoiVklERU8iLCJyb2xlIjoic3BlYWtlciIsInBlcm1pc3Npb25zIjp7ImFkbWluIjpmYWxzZSwiY2FuQ29uc3VtZSI6dHJ1ZSwiY2FuUHJvZHVjZSI6dHJ1ZSwiY2FuUHJvZHVjZVNvdXJjZXMiOnsiY2FtIjp0cnVlLCJtaWMiOnRydWUsInNjcmVlbiI6dHJ1ZX0sImNhblNlbmREYXRhIjp0cnVlLCJjYW5SZWN2RGF0YSI6dHJ1ZSwiY2FuVXBkYXRlTWV0YWRhdGEiOnRydWV9LCJpYXQiOjE3NDEyMTM1MDcsImlzcyI6Ikh1ZGRsZTAxIiwiZXhwIjoxNzQxMjI0MzA3fQ.OYBcyMK507caFjTS7mVpaviV3DqoMc18kNUpJfjTVCtJ1VtK0r5xSlARwsje0vIyIosqIqMFQaonI0fESvQ_ISihFvtvJc - Gq9qMpU - tDzfF5V2v14MvD7w456TiKfFri_ZscPHJ2TJjzVn - a80tQuqggb31R7qqcWbb3LE211WbqkTrlvECOI0vyUETbh3sOMbrtdrkoVw4zNBC3EIhXCD_mD7cScJoGhmsknuQB2D9lGP8RzaEZk - ps - 7MnvztSFpC9tTGsEt - 2ohWobxzngryOtjnb - pdmCe6zwEefKIj6Ib0Xa4YLcqloVhp1YxfjaQlKwvHul4WSxtvgDkdnRiLMDV - 6NS56MXfpcd7sayx6_HtDw9ZpcgDUZw9jvbHv1WkbNmsWJdT95zvu1yOpntF8aSfmbTGFcZsug5s_sETXmjA6tW9PsEn_aagQclBfVB - s3Vty6sRbyCFxcYn6b0U5Nndf5nO3HygVxuysHpMC_BdeX2 - PjaZ2yhBZRnuTpdIiaUp - IhnSy3rEvFp2lrUewCNq5FQofkex - HNDJdw4 - 47cI_v4Lw1qvivpRZDT9i154Y2mGlj_uAK9 - LzVElWfkMQsJLQ_0uDp21FNbha9HwgF6 - lGqifJUhOpAWKvbkM - fWLuYHN1h8J6hYdCG5oYnJdMovj802obO3uv - E | |
// Here's the payload sent to the endpoint | |
// { | |
// roomId: "ytk-qdxu-qek", | |
// permissions: { | |
// admin: false, | |
// canConsume: true, | |
// canProduce: true, | |
// canProduceSources: { | |
// cam: true, | |
// mic: true, | |
// screen: true, | |
// }, | |
// canRecvData: true, | |
// canSendData: true, | |
// canUpdateMetadata: true, | |
// }, | |
// role: "speaker", | |
// metadata: undefined, | |
// } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment