# Authorization

A common use case for NFTs is to act as a login to websites, discord channels or other content. In order to do this, we have to prove 2 things:

1. A wallet owns an NFT from a given collection
2. The NFT record hasn't been spent yet.

To authenticate ownership of an unspent NFT, we recommend the following pattern.\
\
1\. Request Records from the wallet

```typescript
const allRecords = await (wallet?.adapter as LeoWalletAdapter).requestRecords(NFTProgramId);
const nftRecords = allRecords.filter((record: any) => record.data.edition && record.spent === false);
```

We request all of the records for the program and then filter the spent records to get the records representing the NFTs.\
\
2\. Request an Execution of the authorize Function

```typescript
const aleoTransaction = Transaction.createTransaction(
    publicKey!,
    WalletAdapterNetwork.Testnet,
    NFTProgramId,
    'authorize',
    [nftRecords[0], '101u64'], // This should be a random number in production, generated on the back end of a DApp
    0,
);

const txId = await (wallet?.adapter as LeoWalletAdapter).requestExecution(aleoTransaction);
```

The `authorize` function takes two parameters: the NFT record and a `nonce` . The `nonce` should be randomly generated on the backend of the application to prevent the user from choosing a specific random number. This prevents this authorization being used in replay attacks.\
\
3\. Get the execution

```typescript
const newStatus = await (wallet?.adapter as LeoWalletAdapter).transactionStatus(txId);
if (newStatus === 'Finalized') {
    const execution = await (window as any).leoWallet.getExecution(
        transactionId
    );
    console.log(execution);
}
```

The execution takes some time to generate so on some interval, check the status of the transaction. When it's `Finalized`, you can get the execution.&#x20;

In general, it should be faster than a real transaction as no fee proof is generated.

4. Verify the execution

```typescript
const pm = new Aleo.ProgramManager();
const aleoVerifyingKey = Aleo.VerifyingKey.fromString(verifyingKey!);
try {
    await pm.verify_execution(execution.execution, NFTProgram, AUTHORIZE_FUNCTION, true, undefined, aleoVerifyingKey);
    alert('Authorization successful!');
} catch (e) {
    alert('Authorization failed :(');
    console.error(e);
}
```

Additionally, you want to ensure the `execution.global_state_root` exists on chain and that the serial number `execution.transitions[0].inputs[0].id` does not exist on chain. It's extremely important to verify these two pieces of data. Otherwise, malicious users will be able to authorize using either a fraudulent NFT or an already spent NFT.

Together, these checks ensure that a valid record exists on-chain and it has not been spent all without paying any fees.&#x20;

Additionally, by saving the serial number of the record, DApps can automatically invalidate the user session if the serial number appears on chain.

Some tips:<br>

1. To get the verifying key for a given function, you can use the following helper methods:

```typescript
const ALEO_URL = 'https://vm.aleo.org/api/testnet3/';

async function getDeploymentTransaction(programId: string): Promise<any> {
  const response = await fetch(`${ALEO_URL}find/transactionID/deployment/${programId}`);
  const deployTxId = await response.json();
  const txResponse = await fetch(`${ALEO_URL}transaction/${deployTxId}`);
  const tx = await txResponse.json();
  return tx;
}

export async function getVerifyingKey(programId: string, functionName: string): Promise<string> {
  const deploymentTx = await getDeploymentTransaction(programId);

  const allVerifyingKeys = deploymentTx.deployment.verifying_keys;
  const verifyingKey = allVerifyingKeys.filter((vk: any) => vk[0] === functionName)[0][1][0];
  return verifyingKey;
}
```

2. To check if the serial number has been spent, you can use the following method from the Demox RPC:

```javascript
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/json");

var raw = JSON.stringify({
  "jsonrpc": "2.0",
  "id": 1,
  "method": "serialNumbers",
  "params": {
    "serialNumbers": [
      "5228865531938159265544362265315800751823578819356920124710614945837981163945field",
    ]
  }
});

var requestOptions = {
  method: 'POST',
  headers: myHeaders,
  body: raw,
  redirect: 'follow'
};

fetch("http://localhost:3000", requestOptions)
  .then(response => response.text())
  .then(result => console.log(result))
  .catch(error => console.log('error', error));
```

3. The execution from the authorize function cannot be broadcast successfully. It will fail every time. To safely prevent all broadcasting attempts by potentially malicious DApps, ensure the `finalize` statement contains an always fail assertion. For example:&#x20;

```
finalize authorize(
    )
    {
        // fails on purpose, so that the nft is not burned.
        assert_eq(0u8, 1u8);
    }

```
