Hedera Token Service: NFT Token Keys Edge Cases | Hedera Hedera Network Services Token Service Mint and configure tokens and accounts. Consensus Service Verifiable timestamps and ordering of events. Smart Contracts Run Solidity smart contracts. HBAR The Hedera network's native cryptocurrency. Insights How It Works Learn about Hedera from end to end. Explorers View live and historical data on Hedera. Dashboards Analyze network activity and metrics. Network Nodes Understand networks and node types. Devs Start Building Get Started Learn core concepts and build the future. Documentation Review the API and build using your favorite language. Developer Resources Integrations Plugins and microservices for Hedera. Fee Estimator Understand and estimate transaction costs. Open Source Hedera is committed to open, transparent code. Learning Center Learn about web3 and blockchain technologies. Grants Grants & accelerators for your project. Bounties Find bugs. Submit a report. Earn rewards. Ecosystem ECOSYSTEM Hedera Ecosystem Applications, developer tools, network explorers, and more. NFT Ecosystem Metrics Analyze on-chain and market NFT ecosystem metrics. CATEGORIES Web3 Applications Connect into the innovative startups decentralizing the web on Hedera. Enterprise Applications Learn about the Fortune 500 companies decentralizing the web on Hedera. Wallets & Custodians Create a Hedera account to manage HBAR, fungible tokens, and NFTs. Network Explorers Hedera mainnet and testnet graphical network explorers. Developer Tooling Third-party APIs, integrations, and plugins to build apps on Hedera. Grants & Accelerators Boost your project with support from the Hedera ecosystem. Partner Program Explore our partners to bring your vision into reality. Hedera Council Over 30 highly diversified organizations govern Hedera. Use Cases Hedera Solutions Asset Tokenization Studio Open source toolkit for tokenizing assets securely. Stablecoin Studio All-in-one toolkit for stablecoin solutions. Hedera Guardian Auditable carbon markets and traceability. Functional Use Cases Data Integrity & AI Reliable, secure, and ethically governed insights. Sustainability Enabling fair carbon markets with trust. Real-World Asset Tokenization Seamless tokenization of real-world assets and digital at scale. Consumer Engagement & Loyalty Mint, distribute, and redeem loyalty rewards. Decentralized Identity Maintain the lifecycle of credentials. Decentralized Logs Scalable, real-time timestamped events. DeFi Dapps built for the next-generation of finance. NFTs Low, fixed fees. Immutable royalties. Payments Scalable, real-time, and affordable crypto-payments. HBAR Overview Learn about Hedera's token, HBAR. Treasury Management Hedera’s report of the HBAR supply. Governance Decentralized Governance Hedera Council See the world's leading organizations that own Hedera. About Meet Hedera's Board of Directors and team. Journey Watch Hedera's journey to build an empowered digital future for all. Transparent Governance Public Policy Hedera's mission is to inform policy and regulation that impact the industry. Meeting Minutes Immutably recorded on Hedera. Roadmap Follow Hedera's roadmap in its journey to build the future. Resources Company What's New Partners Papers Careers Media Blog Technical Press Podcast Community Events Meetups Store Brand Navigation QUICKSTART Hedera Token Service: NFT Token Keys Edge Cases technical Feb 07, 2023 by Michiel Mulders Developer Relations This technical blog post tries to answer all your questions about token keys, how to use them, and their edge cases. Token keys can be set for any token created using the Hedera Token Service (HTS). This means you can set token keys for both fungible and non-fungible tokens. In this blog post, we'll focus on non-fungible tokens. Here’s an overview of what you’ll learn in this blog post: Which keys can you set for tokens? Why do you set token keys? How to create an NFT using the JavaScript SDK? Token keys test cases Case 1: Can you make changes to an NFT when you don't set an admin key? Case 2: Can the admin key remove other keys? Case 3: Can the admin key update other keys? Case 4: Can the admin key remove itself? Case 5: Can one account ID be set to different keys for the same token? Case 6: Can you assign multiple accounts to a single key? Case 7: Can you set no keys for an NFT? Which keys are considered high-risk for collectible NFTs? Let's start! Which keys can you set for tokens? Here’s an overview of the seven possible keys you can set for a token. Admin key: This key can perform token update and token delete operations on the token. The admin key has the authority to change the supply key, freeze key, pause key, wipe key, and KYC key. It can also update the treasury account of the token. If empty, the token can be perceived as immutable (not able to be updated/deleted). Freeze key: This key is used to freeze or unfreeze token accounts. When an account is frozen, it cannot perform any transactions. KYC key: This key is used to manage the token's KYC (Know Your Customer) information. It can be used to add, update, or remove KYC information for token accounts. Wipe key: This key is used to wipe the balance of a token account. This can be useful in cases where the account owner has lost access to the account or it has been compromised. Supply key: This key is used to manage the total supply of a token. It can be used to mint new tokens or burn existing ones. If the supply key is not set, it’s not possible to mint or burn tokens. Pause key: This key has the authority to pause or unpause a token. Pausing a token prevents the token from participating in all transactions. Fee Schedule key: This key can change the token's custom fee schedule. It must sign a TokenFeeScheduleUpdate transaction. A token without a fee schedule key is immutable, which means you can’t set a custom fee schedule after the token has been created. Why do you set token keys? When creating a token on the Hedera network, setting keys serves several important purposes. Security Setting different keys for different functions ensures that only authorized individuals or entities have control over specific actions related to the token. For example, only the admin key holder can update the token's properties, only the treasury key holder can transfer funds from the token's treasury account, etc. Flexibility Setting multiple keys for the same function allows for multiple individuals or entities to perform that function, providing redundancy and fail-safes. Transparency Setting different keys for different functions also provides transparency and accountability to the token holders and other stakeholders. They can see who has the power to perform certain actions and can hold them accountable for their actions. Compliance Setting different keys for different functions also allows for compliance with regulatory requirements. For example, setting a KYC key allows for the token issuer to comply with know-your-customer regulations and setting a freeze key allows for freezing of accounts that are suspected of engaging in illegal activities. How to create an NFT using the JavaScript SDK? Here's an example of how you can create an NFT with the Hedara Token Service using the Hedera JavaScript SDK, setting all token keys. let nftCreate = await new TokenCreateTransaction() .setTokenName("Fall Collection") .setTokenSymbol("LEAF") .setTokenType(TokenType.NonFungibleUnique) .setDecimals(0) .setInitialSupply(0) .setTreasuryAccountId(treasuryId) // needs to sign .setSupplyType(TokenSupplyType.Finite) .setMaxSupply(5) // Set keys .setAdminKey(adminKey) .setFreezeKey(randomKey) .setKycKey(randomKey) .setWipeKey(randomKey) .setSupplyKey(randomKey) .setPauseKey(randomKey) .setFeeScheduleKey(randomKey) .freezeWith(client); Copy Now, let's take a look at specific test cases related to setting token keys. Token keys test cases In this section, you'll learn about seven test cases related to setting token keys for NFTs. Case 1: Can you make changes to an NFT when you don't set an admin key? Output: The token becomes immutable when you don't set an admin key. This means that none of the token properties can be updated. let nftCreateTx = await new TokenCreateTransaction() .setTokenName("Fall Collection") .setTokenSymbol("LEAF") .setTokenType(TokenType.NonFungibleUnique) .setDecimals(0) .setInitialSupply(0) .setTreasuryAccountId(treasuryId) .setSupplyType(TokenSupplyType.Finite) .setMaxSupply(5) // No admin key, only the required supply key is set .setSupplyKey(treasuryKey) .freezeWith(client) .sign(treasuryKey); Copy Code example: immutable-token.js Case 2: Can the admin key remove other keys or itself? Output: No, it's not possible to remove keys or itself. The admin key is only allowed to update keys. When you set a key to "null" or "undefined", nothing will change. let tokenUpdateTx = await new TokenUpdateTransaction() .setTokenId(tokenId) .setSupplyKey(null) // if you set this to null, nothing happens .freezeWith(client) .sign(adminKey); Copy Code example: all-keys-remove-supply.js Case 3: Can the admin key update other keys? Output: Yes, the admin key has the authority to change the supply key, freeze key, pause key, wipe key, and KYC key. Note that the updated key doesn't need to sign the transaction for it to be assigned to a specific key for the token. In the example below, the supply key is updated with a new supply key. The "newSupplyKey" doesn't need to sign the transaction. Only the "adminKey" needs to sign. let tokenUpdateTx = await new TokenUpdateTransaction() .setTokenId(tokenId) .setSupplyKey(newSupplyKey) .freezeWith(client) .sign(adminKey); Copy Code example: all-keys-update-supply.js Case 4: Can the admin key be updated to a new admin key? Output: Yes, the admin key can be updated when it's set. Both the old and the new admin key must sign the transaction to be successful. let tokenUpdateTx = await new TokenUpdateTransaction() .setTokenId(tokenId) .setAdminKey(newAdminKey) .freezeWith(client) .sign(newAdminKey); let tokenUpdateTxSign = await tokenUpdateTx.sign(adminKey); Copy Code example: token-update-admin-key.js Case 5: Can one account ID be set to different keys for the same token? Output: Yes, you are allowed to set the same account for multiple keys on a token. For instance, our base example uses the "random account ID" for 6 keys. let nftCreate = await new TokenCreateTransaction() .setTokenName("Fall Collection") .setTokenSymbol("LEAF") .setTokenType(TokenType.NonFungibleUnique) .setDecimals(0) .setInitialSupply(0) .setTreasuryAccountId(treasuryId) .setSupplyType(TokenSupplyType.Finite) .setMaxSupply(5) // Set keys .setAdminKey(adminKey) .setFreezeKey(randomKey) // 1 .setKycKey(randomKey) // 2 .setWipeKey(randomKey) // 3 .setSupplyKey(randomKey) // 4 .setPauseKey(randomKey) // 5 .setFeeScheduleKey(randomKey) // 6 .freezeWith(client); Copy Code example: all-keys.js Case 6: Can you assign multiple accounts to a single key? Output: Yes, you can create a KeyList, which acts as a multisig. For instance, you can create a KeyList that contains two accounts and set the signing requirements to 2-out-of-2. Both accounts need to sign when the specific key is required. Below you will find an example with an admin key that has been assigned a 2-out-of-2 KeyList. // Create keylist console.log(`- Generating keylist...`); const keyList = new KeyList([key1.publicKey, key2.publicKey], 2); // 2-out-of-2 // Create NFT console.log(`\n- Creating NFT`); let nftCreate = await new TokenCreateTransaction() .setNodeAccountIds(nodeId) .setTokenName("Fall Collection") .setTokenSymbol("LEAF") .setTokenType(TokenType.NonFungibleUnique) .setDecimals(0) .setInitialSupply(0) .setTreasuryAccountId(treasuryId) // needs to sign .setSupplyType(TokenSupplyType.Finite) .setMaxSupply(5) // Set keys .setAdminKey(keyList) // multisig (keylist) .setSupplyKey(randomKey) .freezeWith(client) .sign(treasuryKey); Copy When you want to execute a transaction, both keys need to sign. // Adding multisig signatures const sig1 = key1.signTransaction(nftCreate); const sig2 = key2.signTransaction(nftCreate); const nftCreateTxSign = nftCreate.addSignature(key1.publicKey, sig1).addSignature(key2.publicKey, sig2); let nftCreateSubmit = await nftCreateTxSign.execute(client); let nftCreateRx = await nftCreateSubmit.getReceipt(client); let tokenId = nftCreateRx.tokenId; console.log(`- Created NFT with Token ID: ${tokenId}`); Copy Code example: token-admin-keylist.js Case 7: Can you set no keys for an NFT? Output: No, the supply key is the only required key when you don't set any other keys for an NFT. If you don't set a supply key, you get the error "TOKEN_HAS_NO_SUPPLY_KEY". let nftCreate = await new TokenCreateTransaction() .setTokenName("Fall Collection") .setTokenSymbol("LEAF") .setTokenType(TokenType.NonFungibleUnique) .setDecimals(0) .setInitialSupply(0) .setTreasuryAccountId(treasuryId) // needs to sign .setSupplyType(TokenSupplyType.Finite) .setMaxSupply(5) // No keys throws error: TOKEN_HAS_NO_SUPPLY_KEY .setSupplyKey(randomKey) // REQUIRED .freezeWith(client); Copy Code example: no-keys.js Which keys are considered high-risk for collectible NFTs? This blog post section explores the different risk scores associated with setting specific keys for non-fungible tokens. Each key receives a relative score and a risk level based on the actions it can carry out. The below risk information is only applicable to NFT collections.  This section aims to educate NFT creators on which keys to set for their NFT collection and to help them understand the implications. Here's an overview of all keys, their risk score, and why they got this score. Admin key [score: 200 - HIGH]: This key can update token properties and change other keys for the NFT. Therefore, it could create a new account and update a specific key for the NFT to the newly created account it owns. Besides that, the admin key can delete an NFT forever.  Wipe key [score: 200 - HIGH]: The wipe key has received an equal risk score of 200 because it can wipe the NFT balance of an account. This key is often set as a backup mechanism when a user loses access to their account, or it's corrupted. The wipe key can remove the account balance of the affected account, and the user can then make a new account and receive the token again. However, this key can also wipe the account balance of users that didn't request this. Freeze key [score: 50 - MEDIUM]: When the freeze key freezes an account, this account can't make any transactions using the specific NFT. In short, the freeze key can exclude someone from using the NFT. KYC key [score: 50 - MEDIUM]: The KYC key can grant or revoke KYC of an account for the NFT's transactions when set. When the KYC for an account is revoked, it's impossible to use the NFT in transactions. Pause key [score: 50 - MEDIUM]: The pause key can pause the entire NFT collection. It means that nobody can use any NFT in transactions.  Fee schedule key [score: 40 - LOW]: The fee schedule key can change the fee users pay when they trade an NFT. The key only received a low risk score because the maximum fee that can be set is 100%. So, a user trading an NFT for 10 Hbar will pay an additional 10 Hbar fee to the treasury account. It's not a big exploit, but one to consider. Supply key: [score: 20 - LOW]: When the supply type is set to "INFINITE", the supply key can mint as many NFTs for a collection as they want. This means the supply key can dilute an NFT project. The risk is eliminated when the supply type is set to FINITE because there's a fixed limit for the number of NFTs this key can mint. Note: When someone buys an NFT from an NFT collection, they want to ensure that nobody can tamper with the NFT itself. Therefore, most projects set no keys, making the NFT immutable. This results in a zero risk score.  If you want to automate the process of calculating risk levels for NFTs, you can use the Hedera NFT Utilities SDK to automate this task. The risk score calculation section shows you how to use this functionality and what output you can expect. Here's a quick example. const { calculateRiskScoreFromData } = require('@hashgraph/nft-utilities'); const tokenInformation = { "admin_key": null, "auto_renew_account": "0.0.784037", "auto_renew_period": 7776000, "freeze_key": null, ... } const results = calculateRiskScoreFromData(tokenInformation); /* Output: * { "riskScore": "0", "riskLevel": "NORISK" } */ Copy Learn more about token keys? ❓ Reach out on Discord or look at the docs about token creation using the Hedera Token Service. 📚 If you want to explore all examples, check the token keys example repository. Share This Back to blog What is gRPC, gRPC-Web, and Proxies? Ed Marquez Pragmatic Blockchain Design Patterns – Integrating Blockchain into Business Processes Michiel Mulders Zero Cost EthereumTransaction on Success: Hedera's New Fee Model for Relay Operators Oliver Thorn Hedera Adopts Chainlink Standard for Cross-Chain Interoperability To Accelerate Ecosystem Adoption Hedera Team Hedera Developer Highlights March 2025 Michiel Mulders Hedera Release Cycle Overview Ed Marquez View All Posts Sign up for the newsletter CONNECT WITH US Transparency Open Source Audits & Standards Sustainability Commitment Carbon Offsets Governance Hedera Council Public Policy Treasury Management Meeting Minutes LLC Agreement Node Requirements Community Events Meetups HBAR Telegram Developer Discord Twitter Community Support FAQ Network Status Developer Discord StackOverflow Brand Brand Guidelines Built on Hedera Logo Hedera Store About Team Partners Journey Roadmap Careers Contact General Inquiry Public Relations © 2018-2025 Hedera Hashgraph, LLC. All trademarks and company names are the property of their respective owners. All rights in the Deutsche Telekom mark are protected by Deutsche Telekom AG. All rights reserved. Hedera uses the third party marks with permission. Terms of Use  |  Privacy Policy