> ## Documentation Index
> Fetch the complete documentation index at: https://docs.inco.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Allowance Voucher

Allowance voucher (aka Session Key) allows owner of a ciphertext to delegate viewing/compute to someone else for a period of time completely off-chain.

<Note>Vouchers are like sessions and are revokable.</Note>

## Getting Started

To create a voucher and grant Bob permission to decrypt on Alice's behalf:

```javascript theme={null}
import { createWalletClient, custom } from 'viem'
import { privateKeyToAccount } from 'viem/accounts';
import { getViemChain, supportedChains, type SupportedChainId } from '@inco/js';
import { Lightning, generateSecp256k1Keypair } from '@inco/js/lite';

// Alice connects her wallet
const walletClient = createWalletClient({
  chain: getViemChain(supportedChains.baseSepolia),
  transport: custom(window.ethereum!)
})

// Alice creates an ephemeral keypair to use for the decryption request
const ephemeralKeypair = generateSecp256k1Keypair();
const ephemeralAccount = privateKeyToAccount(
    `0x${ephemeralKeypair.kp.getPrivate('hex')}`,
);
const zap = await Lightning.latest("testnet", 84532);
// Default session verifier address
const sessionVerfier = "0xc34569efc25901bdd6b652164a2c8a7228b23005";

// Alice creates attested decrypt request and passes the voucher
const voucherWithSig = await zap.grantSessionKeyAllowanceVoucher(
    walletClient,
    ephemeralAccount.address,
    new Date(Date.now() + 1000 * 60 * 60 * 24), // 1 day, in seconds
    sessionVerfier,
);
```

<Note>
  Some specific use cases may require a custom session verifier logic, to for
  example check whether a payment has been made in order to access secrets.
  grantSessionKeyAllowanceVoucher() allows the owner to specify a custom session
  verifier contract address with a custom canUseSession() function that can
  either allow or deny access based on certain on-chain conditions.
</Note>

<Warning>
  Using the default session verifier will give the session key unverified access
  to all user handles for the specified time period.

  DEFAULT\_SESSION\_VERIFIER: (Base Sepolia)
  0xc34569efc25901bdd6b652164a2c8a7228b23005
</Warning>

```Solidity theme={null}
import {ALLOWANCE_GRANTED_MAGIC_VALUE} from "@inco/lightning/src/Types.sol";

struct Session {
    address decrypter;
    uint256 expiresAt;
}

contract MyCustomSessionVerifier {
    function canUseSession(
        bytes32, /* handle */
        address account, /* user trying to use the session */
        bytes memory sharerArgData,
        bytes memory /* requesterArgData */
    ) external view returns (bytes32) {
        Session memory session = abi.decode(sharerArgData, (Session));
        if (session.expiresAt >= block.timestamp && session.decrypter == account) {
            return ALLOWANCE_GRANTED_MAGIC_VALUE;
        }
        return bytes32(0);
    }
}
```

## Attested Decrypt with Voucher/Session Key

The voucher and signature now allow Bob to decrypt any handle that Alice owns using the attestedDecryptWithVoucher() function:

```javascript theme={null}
import type { HexString } from '@inco/js';

// Bob calls the attestedDecryptWithVoucher function with voucher
const decrypted = await zap.attestedDecryptWithVoucher(
    ephemeralKeypair,
    voucherWithSig,
    publicClient,
    ['0x...' as HexString]
);
const plaintext = decrypted[0].plaintext.value;
```

## AttestedCompute with Voucher/Session Key

Bob can also perform attested compute on behalf of Alice using attestedComputeWithVoucher() to check if the value is equal to an expected value:

```javascript theme={null}
import type { AttestedComputeSupportedOps } from '@inco/js/lite';
import type { HexString } from '@inco/js';

const computed = await zap.attestedComputeWithVoucher(
    ephemeralKeypair,
    voucherWithSig,
    publicClient,
    '0x...' as HexString,
    AttestedComputeSupportedOps.Eq,
    100n
);

const plaintext = computed.plaintext.value;
```

## SessionKey Reencrypt

Similarly, Bob can also perform reencryption on behalf of Alice using attestedDecryptWithVoucher() with a reencrypt public key. This is similar to standard [attested decrypt reencryption](../attestations/attested-decrypt#reencryption-for-delegates).

```javascript theme={null}
import type { HexString } from '@inco/js';

// Generate a reencrypt keypair for Bob
const reencryptKeypair = generateSecp256k1Keypair();
const reencryptPubKey = reencryptKeypair.encodePublicKey();

// Bob performs reencryption on behalf of Alice
const reencrypted = await zap.attestedDecryptWithVoucher(
    ephemeralKeypair,
    voucherWithSig,
    publicClient,
    ['0x...' as HexString],
    reencryptPubKey
);

// Bob can decrypt the reencrypted data
const decrypted = await decrypt(
    reencryptKeypair,
    hexToBytes(reencrypted[0].encryptedPlaintext.ciphertext.value)
);
const plaintext = BigInt('0x' + Buffer.from(decrypted).toString('hex'));
```

## Revoking a Voucher

In order to invalidate existing vouchers, you can call this function:

```javascript theme={null}
const txHash = await zap.updateActiveVouchersSessionNonce(walletClient);
```

Which will invalidate all existing vouchers, despite their expiration time.

<Note>
  If you want to selectively revoke access to specific users, your dApp would
  need to handle the logic of reissuing new vouchers to users who still require
  access.
</Note>
