Authorization Function

[Previous << Wallet Provider Spec](https://qiita.com/flowcadence/items/caa67ecf27a07dc2ee29)
[Next >> Introduction](https://qiita.com/flowcadence/items/322bc393bdb2d328ea0d)

https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a#reference-2020832ebee1810a325a

<h1>Overview</h1>

Authorization関数とは、トランザクションにおいてどのFlowアカウントがどの署名者の役割を担うのか、また、提供されたアカウントからの署名をどう受け取るのかを、JS-SDKとFCLが把握できるようにする関数です。
<h1>How to Use an Authorization Function</h1>

承認関数とは、Flow JS-SDKやFCLの承認の代わりに使用できる関数です。承認とは、トランザクションの提案者、支払者、または承認者を指定する際に使用する概念です。承認とは、承認を表すデータ構造か、もしくは呼び出されるとAuthorization Functionと呼ばれる承認を返す関数のことです。このドキュメントでは、後者について説明します。

Authorization Functionの使用の仕方は、Authorization Functionをトランザクションの提案者、支払者、または承認者の認証として指定します。

> `fcl.currentUser().authorization`は、`fcl.authz`にエイリアスされており、それ自体が認証関数です。これは、js-sdkに対し、現在のユーザーのFlowアカウントが署名者として使用されることを通知し、署名関数を提供し、アプリケーションがユーザーのウォレットから署名を要求できるようにします。

Example 1:
```ruby
import * as fcl from "@onflow/fcl"

const myAuthorizationFunction = ... /* An Authorization Function */

const response = fcl.send([
    fcl.transaction`transaction() { prepare(acct: &Account) {} execute { log("Hello, Flow!") } }`,
    fcl.proposer(myAuthorizationFunction),
    fcl.payer(myAuthorizationFunction),
    fcl.authorizers([ myAuthorizationFunction ])
])
```

ビルダー関数である`fcl.proposer`、`fcl.payer`、`fcl.authorizations`はそれぞれ、Authorization Functionを消費し、それを、内部のAccountオブジェクト上のそれが作成するresolveフィールドとして、設定します。

Flow JS-SDKとFCLのresolveフェーズにおいて、[`resolveAccounts`](https://github.com/onflow/fcl-js/blob/master/packages/sdk/src/resolve/resolve.js#L58)が呼び出されると、各内部Accountオブジェクトのresolveフィールドが呼び出されます。つまり、それぞれ適切にAuthorization Functionが呼び出され、アカウントはauthorizationFunctionが返すデータ構造に解決します。これらのアカウントは、`addr`、`keyId`、`tempId`の組み合わせに基づいて重複が排除され、`address ` `keyId`の組み合わせごとに、1つの署名リクエストだけが発生するようにします。 [`resolveSignatures`](https://github.com/onflow/fcl-js/blob/master/packages/sdk/src/resolve/resolve.js#L25)が呼び出された時、各`address ` `keyId`の組み合わせに対する署名関数が呼び出され、各署名者のロールに対して複合署名が返されます。
<h1>How to Create An Authorization Function</h1>

幸運なことに、Authorization Functionの作成は比較的容易です。

Authorization Functionは最低でも次の2つのことを行う必要があります。
* 誰が署名するのか：署名するアカウントと、署名に使用するキーの keyId を知ります
* どのように署名するのか：指定されたアカウントとキーによる署名を取得する方法を知ります

Authorization Functionにはアカウントの概念があります。アカウントは、トランザクションの署名者となり得るものを表します。アカウントには、誰が署名するのか、また、どのように署名するのかが含まれます。Authorization Functionには空のアカウントが渡され、アカウントを返す必要があります。Authorization Functionを作成する際の作業は、主に、署名したいアカウントが署名できるように、このアカウントに情報を入力することです。

例えば、アカウントと keyId が事前に分かっており、署名できる関数があったとします。
```ruby
const ADDRESS = "0xba1132bc08f82fe2"
/* this account on testnet has three keys, we want the one with an index of 1 (has a weight of 1000) */
const KEY_ID = 1
const sign = msg => { /* ... returns signature (for the key above) for supplied message ... */ }
```
私達のAuthorization Functionは、これらを埋めていくことになります。

Example 2:
```ruby
const authorizationFunction = async (account) => {
  /* authorization function need to return an account */
  return {
    ...account, /* bunch of defaults in here, we want to overload some of them though */
    tempId: `${ADDRESS}-${KEY_ID}`, /* tempIds are more of an advanced topic, for 99% of the times where you know the address and keyId you will want it to be a unique string per that address and keyId */
    addr: ADDRESS, /* the address of the signatory */
    keyId: Number(KEY_ID), /* this is the keyId for the accounts registered key that will be used to sign, make extra sure this is a number and not a string */
    signingFunction: async signable => {
      /* Singing functions are passed a signable and need to return a composite signature
         signable.message is a hex string of what needs to be signed. */
      return {
        addr: ADDRESS, /* needs to be the same as the account.addr */
        keyId: Number(KEY_ID), /* needs to be the same as account.keyId, once again make sure its a number and not a string */
        signature: sign(signable.message), /* this needs to be a hex string of the signature, where signable.message is the hex value that needs to be signed */
      }
    }
  }
}
```

<h1>Async stuff</h1>

Authorization FunctionとアカウントのSigning Functionの両方が非同期であることも可能です。つまり、これらの関数の両方が、必要な情報をどこか他の場所から取って来れるということです。あなたの各ユーザーが`userId`を持っているとします。この`userId`から、Authorization Functionのアカウントに必要な、一致するアドレスとキーを返すAPIコールがあるとします。また、あなたのAPIが署名しても問題ないと判断した場合、署名対象（署名に必要な内容を含む）と`userId`がPOST通信された時に、複合署名を返す別のエンドポイントを持つことも可能ます（署名対象には、署名の判断に役立つさまざまな情報が含まれています）。このようなことができる認証関数は、次のような形になります。

Example 3:
```ruby
const getAccount = (userId) => fetch(`/api/user/${userId}/account`).then(d => d.json())
const getSignature = (userId, signable) = fetch(`/api/user/${userId}/sign`, {
  method: "POST",
  headers: { "Content-Type": "application/json"},
  body: JSON.stringify(signable),
})

function authz (userId) {
  return async function authorizationFunction (account) {
    const {addr, keyId} = await getAccount(userId)

    return {
       ...account,
       tempId: `${addr}-${keyId}`,
       addr: addr,
       keyId: Number(keyId),
       signingFunction: signable => {
         return getSignature(userId, signable)
       }
    }
  }
}
```
上記の**Example 3**は**Example 2**と内容は同じですが、認証関数を実行している間に、指定されたユーザーIDに基づいた情報を収集しています。
<h1>How to create a Signing Function</h1>

署名関数の作成も比較的簡単です！

署名関数を作成するには、ペイロードを消費し、署名データ構造(signature data structure)を返す関数を指定します。

Example 4:
```ruby
const signingFunction = ({
  message, /* The encoded string which needs to be used to produce the signature. */
  addr, /* The address of the Flow Account this signature is to be produced for. */
  keyId, /* The keyId of the key which is to be used to produce the signature. */
  roles: {
    proposer, /* A Boolean representing if this signature to be produced for a proposer. */
    authorizer, /* A Boolean representing if this signature to be produced for a authorizer. */
    payer, /* A Boolean representing if this signature to be produced for a payer. */
  }, 
  voucher, /* The raw transactions information, can be used to create the message for additional safety and lack of trust in the supplied message. */
}) => {
  return {
    addr, /* The address of the Flow Account this signature was produced for. */
    keyId, /* The keyId for which key was used to produce the signature. */
    /* The hex encoded string representing the signature of the message. */
    signature: produceSignature(message)
  }
}
```

*Last updated on **Nov 26, 2024** by **Chase Fleming***

翻訳元

https://developers.flow.com/tools/wallet-provider-spec/authorization-function

***
<b>[Previous << Wallet Provider Spec](https://qiita.com/flowcadence/items/caa67ecf27a07dc2ee29)
</b>

[Flow blockchain / Cadence version1.0ドキュメント](https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a) (Authorization Function)

<b>[Next >> Introduction](https://qiita.com/flowcadence/items/322bc393bdb2d328ea0d)</b>