# author_rotateKeys - Centrifuge RPC Method

Generate a new set of session keys on Centrifuge. This method creates fresh cryptographic keys for all session key types (e.g., BABE, GRANDPA, ImOnline, ParaValidator, AuthorityDiscovery) and stores them in the node's local keystore. The returned concatenated public keys must be registered on-chain via `session.setKeys`.

> **Why Centrifuge?** Build on the RWA tokenization platform bridging traditional finance with $1B+ Janus Henderson backing with ERC-7540 RWA standards, multichain via Wormhole, 97% securitization cost savings, and BlockTower $220M fund integration.

## When to Use This Method

`author_rotateKeys` is critical for institutional RWA developers, asset managers, and teams tokenizing real-world assets:

- **Validator Setup** - Generate initial session keys when setting up a new validator on tokenized treasury funds, SME invoice financing, and institutional-grade RWA infrastructure
- **Key Rotation** - Periodically rotate keys for operational security best practices
- **Recovery** - Generate replacement keys after a potential key compromise or node migration
- **Validator Upgrades** - Produce new keys when moving a validator to new hardware

## Best Practices

- Session key rotation requires validator node access -- not available to most API consumers
- Requires node-level authorization and is typically automated by validator infrastructure
- New session keys take effect at the next session boundary
- Most API users should not need this method

## Request Parameters

This method accepts no parameters.

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "author_rotateKeys",
  "params": [],
  "id": 1
}
```

## Response Fields

- `result` (`Bytes, required`): Hex-encoded concatenation of all session key public keys (SCALE-encoded)

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": "0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d..."
}
```

## Error Responses

### Error Response

- Code: `-32603`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32603,
    "message": "RPC call is unsafe to be called externally"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Rust

```bash
# Call on your local validator node only
curl -X POST http://127.0.0.1:9944 \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "author_rotateKeys",
    "params": [],
    "id": 1
  }'
```

```javascript
import { ApiPromise, WsProvider, Keyring } from '@polkadot/api';

// Connect to your LOCAL validator node
const provider = new WsProvider('ws://127.0.0.1:9944');
const api = await ApiPromise.create({ provider });

// Generate new session keys
const keys = await api.rpc.author.rotateKeys();
console.log('New session keys:', keys.toHex());

// Register the keys on-chain
const keyring = new Keyring({ type: 'sr25519' });
const validatorAccount = keyring.addFromUri('//ValidatorStash');

const tx = api.tx.session.setKeys(keys, '0x');
const hash = await tx.signAndSend(validatorAccount);
console.log('setKeys transaction hash:', hash.toHex());

await api.disconnect();
```

```python
import requests

def rotate_keys():
    # Always call on your LOCAL validator node
    url = 'http://127.0.0.1:9944'

    payload = {
        'jsonrpc': '2.0',
        'method': 'author_rotateKeys',
        'params': [],
        'id': 1
    }

    response = requests.post(url, json=payload)
    result = response.json()

    if 'error' in result:
        raise Exception(f"Error: {result['error']['message']}")

    return result['result']

try:
    session_keys = rotate_keys()
    print(f'New session keys: {session_keys}')
    print('Next step: Submit session.setKeys extrinsic with these keys')
except Exception as e:
    print(f'Failed: {e}')
```

```rust
use subxt::{OnlineClient, PolkadotConfig};
use serde_json::Value;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Connect to LOCAL validator node
    let api = OnlineClient::<PolkadotConfig>::from_url(
        "ws://127.0.0.1:9944"
    ).await?;

    let keys: Value = api.rpc()
        .request("author_rotateKeys", subxt::rpc_params![])
        .await?;

    println!("New session keys: {}", keys);
    println!("Submit session.setKeys with these keys");

    Ok(())
}
```

## Common Use Cases

### 1. Complete Validator Setup Workflow

Full end-to-end validator setup on Centrifuge:

```javascript
async function setupValidator(api, stashAccount) {
  // Step 1: Generate session keys
  const keys = await api.rpc.author.rotateKeys();
  console.log('Generated session keys:', keys.toHex());

  // Step 2: Register keys on-chain
  const setKeysTx = api.tx.session.setKeys(keys, '0x');
  await new Promise((resolve, reject) => {
    setKeysTx.signAndSend(stashAccount, ({ status, events }) => {
      if (status.isFinalized) {
        const success = events.some(({ event }) =>
          api.events.system.ExtrinsicSuccess.is(event)
        );
        if (success) {
          console.log('Session keys registered successfully');
          resolve();
        } else {
          reject(new Error('setKeys transaction failed'));
        }
      }
    });
  });

  // Step 3: Verify registration
  const nextKeys = await api.query.session.nextKeys(stashAccount.address);
  console.log('Keys registered for next session:', nextKeys.isSome);
}
```

### 2. Scheduled Key Rotation

Automate periodic key rotation for security:

```javascript
async function scheduleKeyRotation(api, validatorAccount, intervalDays = 30) {
  const intervalMs = intervalDays * 24 * 60 * 60 * 1000;

  async function rotateAndRegister() {
    try {
      const newKeys = await api.rpc.author.rotateKeys();
      console.log(`Rotated keys at ${new Date().toISOString()}`);

      const tx = api.tx.session.setKeys(newKeys, '0x');
      await tx.signAndSend(validatorAccount);
      console.log('New keys registered - active next session');
    } catch (error) {
      console.error('Key rotation failed:', error.message);
    }
  }

  // Initial rotation
  await rotateAndRegister();

  // Schedule future rotations
  setInterval(rotateAndRegister, intervalMs);
}
```

## Validator Setup Workflow

1. **Generate keys** - Call `author_rotateKeys` on your validator node
2. **Register on-chain** - Submit `session.setKeys(keys, proof)` extrinsic from your stash account
3. **Wait for session** - Keys become active at the start of the next session
4. **Verify** - Query `session.nextKeys` to confirm registration

## Security Considerations

- **Local access only** - Only call this method on your own validator node via localhost
- **Never expose publicly** - This RPC method is marked as `unsafe` and should not be accessible from the internet
- **Keystore security** - Session keys are stored in the node's keystore directory on disk
- **Rotate regularly** - Follow a key rotation schedule to limit exposure from potential compromises
- **Backup awareness** - New keys replace old ones in the keystore; old keys cannot be recovered

## Related Methods

- `author_hasSessionKeys` - Check if session keys exist in the keystore
- [`author_submitExtrinsic`](https://www.dwellir.com/docs/centrifuge/author_submitExtrinsic) - Submit the `setKeys` transaction
- [`author_pendingExtrinsics`](https://www.dwellir.com/docs/centrifuge/author_pendingExtrinsics) - View pending transactions
- `session_nextKeys` - Query registered session keys on-chain
