Account Key Rotation
Aptos Move accounts have a public address, an authentication key, a public key, and a private key. The public address is permanent, always matching the account’s initial authentication key.
The Aptos account model facilitates the unique ability to rotate an account’s private key. Since an account’s address is the initial authentication key, the ability to sign for an account can be transferred to another private key without changing its public address.
In this guide, we show examples of how to rotate an account’s authentication key using the CLI and few of the various Aptos SDKs.
Here are the installation links for the SDKs we will cover in this example:
Some of the following examples use private keys. Do not share your private keys with anyone.
Aptos CLI
Initialize devnet profiles
Run the following to initialize test profiles. Leave the inputs blank each time you’re prompted for a private key.
aptos init --profile test-profile-1 --network devnet --assume-yes
aptos init --profile test-profile-2 --network devnet --assume-yes
aptos init --profile test-profile-3 --network devnet --assume-yes
Get private key
To view test-profile-2
with its private key hidden:
aptos config show-profiles --profile test-profile-2
To show the profile’s private key:
aptos config show-private-key --profile test-profile-2
If your machine has jq
, a lightweight and flexible command-line JSON
processor, you can pipe the private key directly into an environment variable:
export TEST_PROFILE_2_PRIVATE_KEY=$(
aptos config show-private-key --profile test-profile-2 \
| jq -r '.Result'
)
echo $TEST_PROFILE_2_PRIVATE_KEY
Otherwise, manually copy and paste:
export TEST_PROFILE_2_PRIVATE_KEY=0x...
Rotate authentication key
Rotate the account address associated with test-profile-1
to authenticate via
the private key from test-profile-2
private key:
aptos account rotate-key \
--new-private-key $TEST_PROFILE_2_PRIVATE_KEY \
--profile test-profile-1 \
--save-to-profile test-profile-1-rotated
Once the transaction completes, compare the profiles:
aptos config show-profiles --profile test-profile-1
aptos config show-profiles --profile test-profile-1-rotated
aptos config show-profiles --profile test-profile-2
Note that test-profile-1
has a different public key from
test-profile-1-rotated
, which has the same public key as test-profile-2
.
This is because test-profile-1
is an outdated representation of the account
that is now accurately represented by test-profile-1-rotated
, which is
authenticated via the same private key as test-profile-2
.
If your machine has jq
, you can easily compare the public keys via:
export PROFILE_1_PUB_KEY=$(
aptos config show-profiles --profile test-profile-1 \
| jq -r '.Result["test-profile-1"].public_key'
)
export PROFILE_1_ROTATED_PUB_KEY=$(
aptos config show-profiles --profile test-profile-1-rotated \
| jq -r '.Result["test-profile-1-rotated"].public_key'
)
export PROFILE_2_PUB_KEY=$(
aptos config show-profiles --profile test-profile-2 \
| jq -r '.Result["test-profile-2"].public_key'
)
echo $PROFILE_1_PUB_KEY
echo $PROFILE_1_ROTATED_PUB_KEY
echo $PROFILE_2_PUB_KEY
Compare authentication keys listed onchain
First you’ll need to get the account addresses. Note that test-profile-1
and
test-profile-1-rotated
have the same account address.
If your machine has jq
, you can easily store account addresses via the
following:
export TEST_ADDRESS_1=$(
aptos config show-profiles --profile test-profile-1 \
| jq -r '.Result["test-profile-1"].account'
)
export TEST_ADDRESS_2=$(
aptos config show-profiles --profile test-profile-2 \
| jq -r '.Result["test-profile-2"].account'
)
echo $TEST_ADDRESS_1
echo $TEST_ADDRESS_2
Otherwise, you’ll need to re-run the show-profiles
commands from the last step
and manually copy the addresses:
export TEST_ADDRESS_1=0x...
export TEST_ADDRESS_2=0x...
To view the authentication keys of the two accounts onchain:
aptos move view \
--args address:0x$TEST_ADDRESS_1 \
--function-id 0x1::account::get_authentication_key \
--profile test-profile-1
aptos move view \
--args address:0x$TEST_ADDRESS_2 \
--function-id 0x1::account::get_authentication_key \
--profile test-profile-1
Note that --profile test-profile-1
is repeated across both calls since in this
case the profile is only used to specify the REST URL for the query.
Inspect lookup addresses
The onchain originating address table is a reverse lookup table that maps from an authentication key to an account address.
The originating address table is only updated upon key rotation, and maps from an authentication key to at most one account address, which means that theoretically a given private key can authenticate up to two accounts at the same time:
- The account address derived from the private key during standard account
generation, assuming the account has not undergone any key rotations
(
test-profile-2
). - A second arbitrary address, which has had its authentication key rotated to
the given private key (
test-profile-1-rotated
).
The command aptos account lookup-address
checks if a there is an entry in the
originating address table for a given private key, and if so, returns the
reverse lookup address. If not, it simply returns the account address derived
from the private key, hence the following commands all return TEST_ADDRESS_1
:
aptos account lookup-address --profile test-profile-1
aptos account lookup-address --profile test-profile-2
aptos account lookup-address --profile test-profile-1-rotated
echo $TEST_ADDRESS_1
This is because the private key in test-profile-1
doesn’t have a corresponding
authentication key entry in the originating address able, while the private key
that authenticates both test-profile-2
and test-profile-1-rotated
does
have a corresponding entry, which maps to TEST_ADDRESS_1
due to the key
rotation.
Attempt invalid rotations
Since the private key that authenticates test-profile-2
and
test-profile-1-rotated
is now in the originating address table, it is not
possible to perform a key rotation operation that rotates either to the
corresponding authentication key, or from the corresponding authentication
key for an account besides TEST_ADDRESS_1
.
For example, test-profile-2
may not be rotated to authenticate with the
private key of test-profile-1
(rotate from the authentication key for an
account other than TEST_ADDRESS_1
):
If your machine has jq
, you can pipe the private key of test-profile-1
directly into an environment variable:
export TEST_PROFILE_1_PRIVATE_KEY=$(
aptos config show-private-key --profile test-profile-1 \
| jq -r '.Result'
)
echo $TEST_PROFILE_1_PRIVATE_KEY
Otherwise, manually copy and paste:
aptos config show-private-key --profile test-profile-1
export TEST_PROFILE_1_PRIVATE_KEY=0x...
Attempt an invalid rotation from TEST_ADDRESS_2
, which is authenticated by the
private key that also authenticates TEST_ADDRESS_1
:
aptos account rotate-key \
--new-private-key $TEST_PROFILE_1_PRIVATE_KEY \
--profile test-profile-2 \
--save-to-profile test-profile-2-rotated
This command fails because the underlying Move logic for key rotation expects
that the originating address table maps from the given authentication key to the
address that is rotating its authentication key, which is not the case here
(because the table was initialized with an entry mapping to TEST_ADDRESS_1
,
not TEST_ADDRESS_2
):
Similarly, it is not possible to rotate a different account address to the
private key that authenticates test-profile-2
and test-profile-1-rotated
(rotate to authentication key that is already in the originating address table):
aptos account rotate-key \
--new-private-key $TEST_PROFILE_2_PRIVATE_KEY \
--profile test-profile-3 \
--save-to-profile test-profile-3-rotated
Hence it is best practice to only authenticate one account with a given private key at a time.
Delete the test profiles
aptos config delete-profile --profile test-profile-1
aptos config delete-profile --profile test-profile-2
aptos config delete-profile --profile test-profile-1-rotated
aptos config delete-profile --profile test-profile-3
TypeScript
This program creates two accounts on devnet, Alice and Bob, funds them, then rotates the Alice’s authentication key to that of Bob’s.
View the full example for this code here.
The function to rotate is very simple:
Commands to run the example script:
Navigate to the typescript SDK directory, install dependencies and run
rotate_key.ts
cd ~/aptos-core/ecosystem/typescript/sdk/examples/typescript-esm
pnpm install && pnpm rotate_key
rotate_key.ts output
Account Address Auth Key Private Key Public Key
------------------------------------------------------------------------------------------------
Alice 0x213d...031013 '0x213d...031013' '0x00a4...b2887b' '0x859e...08d2a9'
Bob 0x1c06...ac3bb3 0x1c06...ac3bb3 0xf2be...9486aa 0xbbc1...abb808
...rotating...
Alice 0x213d...031013 '0x1c06...ac3bb3' '0xf2be...9486aa' '0xbbc1...abb808'
Bob 0x1c06...ac3bb3 0x1c06...ac3bb3 0xf2be...9486aa 0xbbc1...abb808
Python
This program creates two accounts on devnet, Alice and Bob, funds them, then rotates the Alice’s authentication key to that of Bob’s.
View the full example for this code here.
Here’s the relevant code that rotates Alice’s keys to Bob’s:
Commands to run the example script:
Navigate to the python SDK directory, install dependencies and run
rotate_key.ts
cd aptos-core/ecosystem/python/sdk
poetry install && poetry run python -m examples.rotate-key
rotate_key.py output
Account Address Auth Key Private Key Public Key
------------------------------------------------------------------------------------------------
Alice 0x213d...031013 '0x213d...031013' '0x00a4...b2887b' '0x859e...08d2a9'
Bob 0x1c06...ac3bb3 0x1c06...ac3bb3 0xf2be...9486aa 0xbbc1...abb808
...rotating...
Alice 0x213d...031013 '0x1c06...ac3bb3' '0xf2be...9486aa' '0xbbc1...abb808'
Bob 0x1c06...ac3bb3 0x1c06...ac3bb3 0xf2be...9486aa 0xbbc1...abb808