# 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);
    }

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://art.privacypride.com/authorization.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
