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

# Authorization context

> Easily sign requests to the Privy API with authorization keys, users, and key quorums.

The authorization context is an SDK abstraction that allows you to easily sign requests to the Privy
API with authorization keys, users, and key quorums.

## Building the `AuthorizationContext`

When making a request to the Privy API that requires an authorization signature, you can build your
authorization context, depending on if the signer of the request is an authorization key, a user, or
a key quorum, per the instructions below

### Authorization key

If the signer of the request is an authorization key, get the private key(s) that you saved locally
when creating your signer in the Privy API or Dashboard.
See the guide on [authorization keys](/controls/authorization-keys/keys/create/key) for more details.

The raw private key(s) can then be added to the authorization context, to sign requests to the Privy
API.

<CodeGroup>
  ```java Java highlight={2} theme={"system"}
  AuthorizationContext authorizationContext = AuthorizationContext.builder()
      .addAuthorizationPrivateKey("authorization-key")
      .build();
  ```

  ```ts @privy-io/node highlight={4} theme={"system"}
  import {AuthorizationContext} from '@privy-io/node';

  const authorizationContext: AuthorizationContext = {
    authorization_private_keys: ['authorization-key']
  };
  ```

  ```rust Rust highlight={4} theme={"system"}
  use privy_rs::{AuthorizationContext, PrivateKey};

  let ctx = AuthorizationContext::new().push(
      PrivateKey("authorization-key".to_string())
  );
  ```

  ```go Go highlight={4} theme={"system"}
  import "github.com/privy-io/go-sdk/authorization"

  authCtx := &authorization.AuthorizationContext{
      PrivateKeys: []string{"authorization-key"},
  }
  ```

  ```ruby Ruby highlight={2} theme={"system"}
  ctx = Privy::Authorization::AuthorizationContext.build(
    authorization_private_keys: ["authorization-key"]
  )
  ```
</CodeGroup>

### User

If the signer of the request is a user, you can add the user's JWT to the authorization context.

See the guide on [user owners and signers](/controls/authorization-keys/keys/create/user/request)
for more details.

<CodeGroup>
  ```java Java highlight={2} theme={"system"}
  AuthorizationContext authorizationContext = AuthorizationContext.builder()
      .addUserJwt("user-jwt")
      .build();
  ```

  ```ts @privy-io/node highlight={4} theme={"system"}
  import {AuthorizationContext} from '@privy-io/node';

  const authorizationContext: AuthorizationContext = {
    user_jwts: ['user-jwt']
  };
  ```

  ```rust Rust highlight={4} theme={"system"}
  use privy_rs::{AuthorizationContext, JwtUser, PrivyClient};

  let client = PrivyClient::new(app_id, app_secret)?;
  let jwt_user = JwtUser(client.clone(), "user-jwt".to_string());

  let ctx = AuthorizationContext::new().push(jwt_user);
  ```

  ```go Go highlight={4} theme={"system"}
  import "github.com/privy-io/go-sdk/authorization"

  authCtx := &authorization.AuthorizationContext{
      UserJwts: []string{"user-jwt"},
  }
  ```

  ```ruby Ruby highlight={2} theme={"system"}
  ctx = Privy::Authorization::AuthorizationContext.build(
    user_jwts: ["user-jwt"]
  )
  ```
</CodeGroup>

### Computing signatures directly

<Warning>
  This is an advanced use case. Whenever possible, you should opt to use one of the mechanisms above.
</Warning>

If you need to create [authorization signatures](/api-reference/authorization-signatures) while keeping the signing key outside of the SDK (e.g. in a separate KMS), you can pass in a sign function to the SDK's authorization context, or even pass in the signature to use directly.

#### Sign functions

You can pass in a sign function to the SDK's authorization context, which will be called with the
payload to sign when the request is made.
The sign functions should perform an ECDSA P-256 signature on the payload received, and return the
base64-encoded signature.

<CodeGroup>
  ```java Java theme={"system"}
  // This feature is not yet supported in the Java SDK.
  ```

  ```ts @privy-io/node {skip-check} theme={"system"}
  async function mySignFunction(payload: Uint8Array): Promise<string> {
    // Perform an ECDSA P-256 signature on the payload
    // This is an example using a fictitious KMS API call.
    const signature = await kms.sign(payload);
    return signature; // This should be a base64-encoded string
  }

  const authorizationContext: AuthorizationContext = {
    sign_functions: [mySignFunction]
  };
  ```

  ```rust Rust theme={"system"}
  //! This newtype is just a convenience blanket implementation.
  //! You can of course just implement the trait for your own types.
  //!
  //! See the API reference for details:
  //! https://docs.rs/privy_rs/latest/privy_rs/trait.IntoSignature.html
  //! https://docs.rs/privy_rs/latest/privy_rs/trait.IntoKey.html

  use privy_rs::{AuthorizationContext, FnSigner};

  // Create a custom signer using a closure with FnSigner wrapper
  let custom_signer = FnSigner(|message: &[u8]| async move {
      // Perform an ECDSA P-256 signature on the payload
      // This is an example using a fictitious KMS API call.
      let signature_bytes = kms_sign(message).await?;
      let signature_b64 = general_purpose::STANDARD.encode(&signature_bytes);
      Ok(Signature {
          signature: signature_b64,
          key_id: "custom-key".to_string()
      })
  });

  let ctx = AuthorizationContext::new().push(custom_signer);
  ```

  ```go Go theme={"system"}
  import "github.com/privy-io/go-sdk/authorization"

  // Implement the AuthorizationSigner interface
  type MySigner struct{}

  func (s *MySigner) Sign(ctx context.Context, payload []byte) (string, error) {
      // Custom signing logic
      return "signature", nil
  }

  authCtx := &authorization.AuthorizationContext{
      Signers: []authorization.AuthorizationSigner{&MySigner{}},
  }
  ```

  ```ruby Ruby theme={"system"}
  sign_fn = ->(payload) {
    # Custom signing logic
  }

  ctx = Privy::Authorization::AuthorizationContext.build(sign_fns: [sign_fn])
  ```
</CodeGroup>

<Info>
  The binary payload received by the sign function is already formatted and ready to be signed.
  There is no need to canonicalize or serialize the payload before signing when using this method.
</Info>

#### Adding a signature manually

If instead you want to encode and sign the request payload manually, you can do so by using the utilities provided by the SDK.

<Steps>
  <Step title="1. Get the encoded request payload to sign over">
    Use the `formatRequestForAuthorizationSignature` utility to get the encoded request payload to sign over.

    <CodeGroup>
      ```java Java focus={12-23} theme={"system"}
      // Build the request, in this case an ethereum personal_sign request
      EthereumPersonalSignRpcInputParams params = EthereumPersonalSignRpcInputParams.builder()
          .message(message)
          .encoding(Encoding.of(EncodingUtf8.UTF8))
          .build();

      EthereumPersonalSignRpcInput request = EthereumPersonalSignRpcInput.builder()
          .method(EthereumPersonalSignRpcInputMethod.PERSONAL_SIGN)
          .params(params)
          .build();

      byte[] encodedRequestPayload = privyClient
          .utils()
          .requestFormatter()
          .formatRequestForAuthorizationSignature(
              new WalletApiRequestSignatureInput(
                  1,
                  request,
                  HttpMethod.POST,
                  "https://api.privy.io/wallets/wallet-id/rpc",
                  null
              )
          );
      ```

      ```ts @privy-io/node theme={"system"}
      import {formatRequestForAuthorizationSignature} from '@privy-io/node';

      const encodedRequestPayload: Uint8Array = formatRequestForAuthorizationSignature({
        version: 1,
        method: 'POST',
        url: 'https://api.privy.io/wallets/wallet-id/rpc',
        body: {
          method: 'personal_sign',
          params: {message: 'Hello from Privy!', encoding: 'utf-8'}
        },
        headers: {'privy-app-id': 'your-privy-app-id'}
      });
      ```

      ```rust Rust theme={"system"}
      use privy_rs::format_request_for_authorization_signature;
      use privy_rs::generated::types::*;

      // Build the request, in this case an ethereum personal_sign request
      let params = EthereumPersonalSignRpcInputParams {
          message: "Hello from Privy!".to_string(),
          encoding: Some(EthereumPersonalSignRpcInputParamsEncoding::Utf8),
      };

      let request = EthereumPersonalSignRpcInput {
          method: EthereumPersonalSignRpcInputMethod::PersonalSign,
          params,
      };

      let encoded_request_payload = format_request_for_authorization_signature(
          &app_id,
          crate::Method::POST,
          "https://api.privy.io/wallets/wallet-id/rpc".to_string(),
          &request,
          None,
      )?;
      ```

      ```go Go theme={"system"}
      import "github.com/privy-io/go-sdk/authorization"

      payload, err := authorization.FormatRequestForAuthorizationSignature(
          authorization.WalletApiRequestSignatureInput{
              // request details
          },
      )
      ```

      ```ruby Ruby theme={"system"}
      input = Privy::Authorization::WalletApiRequestSignatureInput.build(
        method: :post,
        url: "https://api.privy.io/wallets/wallet-id/rpc",
        body: {
          method: "personal_sign",
          params: {message: "Hello from Privy!", encoding: "utf-8"}
        },
        headers: {"privy-app-id" => "your-privy-app-id"}
      )

      encoded_request_payload = Privy::Authorization.format_request_for_authorization_signature(input)
      ```
    </CodeGroup>
  </Step>

  <Step title="2. Produce the signature">
    The logic for producing the signature is fully dependent on the details of your implementation.
    Simply make sure to sign over the byte array returned in the previous step.
  </Step>

  <Step title="3. Add the signature to the authorization context">
    <CodeGroup>
      ```java Java highlight={2} theme={"system"}
      AuthorizationContext authorizationContext = AuthorizationContext.builder()
          .addSignature("signature-you-produced")
          .build();
      ```

      ```ts @privy-io/node highlight={3,5} theme={"system"}
      import {AuthorizationContext} from '@privy-io/node';

      const authorizationContext: AuthorizationContext = {
        signatures: ['signature-you-produced']
      };
      ```

      ```rust Rust highlight={3,13,18} theme={"system"}
      //! `p256::ecdsa::Signature` implements `IntoSignature`, so
      //! you can push it directly to the authorization context.

      use privy_rs::AuthorizationContext;
      use p256::{ecdsa::Signature, generic_array::GenericArray};
      use base64::{Engine as _, engine::general_purpose};

      let ctx = AuthorizationContext::new();

      // Option 1: Add a pre-computed signature from bytes
      let signature_bytes = general_purpose::STANDARD.decode("your-base64-signature")?;
      let signature = Signature::from_bytes(GenericArray::from_slice(&signature_bytes))?;
      let ctx = ctx.push(signature);

      // Option 2: Add a signature from DER format
      let der_bytes = &[/* your DER encoded signature bytes */];
      let signature = Signature::from_der(der_bytes)?;
      let ctx = ctx.push(signature);
      ```

      ```go Go theme={"system"}
      import "github.com/privy-io/go-sdk/authorization"

      authCtx := &authorization.AuthorizationContext{
          Signatures: []string{"pre-computed-signature"},
      }
      ```

      ```ruby Ruby highlight={2} theme={"system"}
      ctx = Privy::Authorization::AuthorizationContext.build(
        signatures: ["signature-you-produced"]
      )
      ```
    </CodeGroup>
  </Step>
</Steps>

## Key quorums

You may combine the different signing mechanisms in the authorization context to produce a fully
customizable key quorum.

For instance, you may want to keep a wallet under control of both a user and an authorization key,
requiring both signatures to authorize an action. This would be a 2-of-2 key quorum, and can be
built by combining both the "user jwt" and "authorization private key" properties, as shown below.

<CodeGroup>
  ```java Java theme={"system"}
  // Example: A 2-of-2 key quorum, of a user and an authorization private key
  AuthorizationContext authorizationContext = AuthorizationContext.builder()
      .addUserJwt("user-jwt")
      .addAuthorizationPrivateKey("authorization-key")
      .build();
  ```

  ```ts @privy-io/node theme={"system"}
  import {AuthorizationContext} from '@privy-io/node';

  // Example: A 2-of-2 key quorum, of a user and an authorization private key
  const authorizationContext: AuthorizationContext = {
    user_jwts: ['user-jwt'],
    authorization_private_keys: ['authorization-key']
  };
  ```

  ```rust Rust theme={"system"}
  // Example: A 2-of-2 key quorum, of a user and an authorization private key
  use privy_rs::{AuthorizationContext, JwtUser, PrivateKey, PrivyClient};

  let client = PrivyClient::new(app_id, app_secret)?;

  // Add user JWT for user-based authorization
  let jwt_user = JwtUser(client.clone(), "user-jwt".to_string());

  // Add private key for authorization key-based signing
  let auth_key = PrivateKey("authorization-key".to_string());

  let ctx = AuthorizationContext::new()
      .push(jwt_user)
      .push(auth_key);
  ```

  ```go Go theme={"system"}
  import "github.com/privy-io/go-sdk/authorization"

  authCtx := &authorization.AuthorizationContext{
      PrivateKeys: []string{"authorization-key"},
      UserJwts:    []string{"user-jwt-token"},
  }
  ```

  ```ruby Ruby theme={"system"}
  # Example: A 2-of-2 key quorum, of a user and an authorization private key
  ctx = Privy::Authorization::AuthorizationContext.build(
    user_jwts: ["user-jwt"],
    authorization_private_keys: ["authorization-key"]
  )
  ```
</CodeGroup>

See our guide on [key quorums](/controls/key-quorum/overview) for more details.
