Skip to content

Commit

Permalink
docs: Update API reference links and SiweAuth contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
matevz committed Feb 3, 2025
1 parent fd1bc99 commit d21e133
Showing 1 changed file with 40 additions and 22 deletions.
62 changes: 40 additions & 22 deletions docs/develop/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,11 @@ authentication flow:
![SIWE authentication flow on Sapphire](../diagrams/siwe-sapphire-flow.mmd.svg)

Consider the `MessageBox` contract from [above](#authenticated-view-calls), and
let's extend it with SIWE:
let's extend it with [SiweAuth]:

```solidity
import {SiweAuth} from "@oasisprotocol/sapphire-contracts/contracts/auth/SiweAuth.sol";
contract MessageBox is SiweAuth {
address private _owner;
string private _message;
Expand All @@ -167,7 +169,7 @@ contract MessageBox is SiweAuth {
_owner = msg.sender;
}
function getSecretMessage(bytes calldata token) external view onlyOwner(token) returns (string memory) {
function getSecretMessage(bytes memory token) external view onlyOwner(token) returns (string memory) {
return _message;
}
Expand All @@ -193,6 +195,7 @@ On the client side, the code running inside a browser needs to make sure that
the session token for making authenticated calls is valid. If not, the browser
requests a wallet to sign a log-in message and fetch a fresh session token.


```typescript
import {SiweMessage} from 'siwe';

Expand Down Expand Up @@ -234,28 +237,36 @@ your Web3 endpoint.

:::

[demo-starter]: https://github.com/oasisprotocol/demo-starter/tree/matevz/sapphire-paratime-2.0
[demo-starter]: https://github.com/oasisprotocol/demo-starter
[SiweAuth]: https://api.docs.oasis.io/sol/sapphire-contracts/contracts/auth/SiweAuth.sol/contract.SiweAuth.html
[EIP-4361]: https://eips.ethereum.org/EIPS/eip-4361
[single sign-on]: https://en.wikipedia.org/wiki/Single_sign-on
[sp-npm]: https://www.npmjs.com/package/@oasisprotocol/sapphire-paratime

### via signed queries

The [EIP-712] proposal defines a method to show data to the user in a structured
fashion so they can verify it and sign it. On the frontend, apps signing a view
call would require user interaction each time—sometimes even multiple times per
page—which is bad UX that frustrates users. Backend services on the other hand
can have direct access to an Ethereum wallet without needing user interaction.
This is possible because these services do not access unspecified websites, and
only execute trusted code.

The Sapphire wrappers for [Go][sp-go] and [Python][sp-py] will make sure to
**automatically sign any view calls** you make to a contract running on Sapphire
using the proposed [EIP-712] method. Suppose we want to store the private key of
an account used to sign the view calls inside a `PRIVATE_KEY` environment
variable. The following snippets demonstrate how to trigger signed queries
without any changes to the original `MessageBox` contract from
[above](#authenticated-view-calls).
[EIP-712] proposed a method to show data to the user in a structured fashion so
they can verify it before signing. In the browser however, apps requiring signed
view calls would trigger user interaction with their wallet each time—sometimes
even multiple times per page—which is bad UX that frustrates users. Backend
services on the other hand often have direct access to an Ethereum wallet (e.g.
a secret key stored in the environment variable) without needing user
interaction. This is possible because a backend service connects to a trusted
site and executes trusted code, so it's fine to sign the necessary view calls
non interactively.

The Sapphire wrappers for [Go][sp-go] and [Python][sp-py] will **sign any view
call** you make to a contract deployed on Sapphire using the aforementioned
[EIP-712]. Suppose we want to store the private key of an account used to sign
the view calls inside a `PRIVATE_KEY` environment variable. The following
snippets demonstrate how to trigger signed queries **without any changes to the
original `MessageBox` contract from [above](#authenticated-view-calls)**.

[sp-go]: https://github.com/oasisprotocol/sapphire-paratime/tree/main/clients/go
[sp-py]: https://github.com/oasisprotocol/sapphire-paratime/tree/main/clients/py

[wrapped-go]: https://pkg.go.dev/github.com/oasisprotocol/sapphire-paratime/clients/go#WrapClient
[wrapped-py]: https://api.docs.oasis.io/py/sapphirepy/sapphirepy.html#sapphirepy.sapphire.wrap

<Tabs>
<TabItem value="Go">
Expand Down Expand Up @@ -351,11 +362,18 @@ def get_c10l_message(address: str, network_name: Optional[str] = "sapphire-local
</TabItem>
</Tabs>

[sp-go]: https://github.com/oasisprotocol/sapphire-paratime/tree/main/clients/go
[sp-py]: https://github.com/oasisprotocol/sapphire-paratime/tree/main/clients/py
:::tip

[wrapped-go]: https://pkg.go.dev/github.com/oasisprotocol/sapphire-paratime/clients/go#WrapClient
[wrapped-py]: https://github.com/oasisprotocol/sapphire-paratime/blob/main/clients/py/sapphirepy/sapphire.py#L268
If your smart contract needs to support view calls from both the frontend and
the backend, then take the [SIWE approach](#via-siwe-token). The backend
implementation then depends on your programming language:

- **Go and Python**: Pass an empty string as a `token` parameter to your smart
contract and let the wrapper sign the view call using EIP-712. Since
`msg.sender` will be defined, the `isOwner` modifier will pass just fine.
- **TypeScript**: Recycle the frontend client-side code
[from above](#via-siwe-token) to generate the SIWE message, perform the
authentication and pass it in the view call.

[Oasis starter project for Go]: https://github.com/oasisprotocol/demo-starter-go
[Oasis starter project for Python]: https://github.com/oasisprotocol/demo-starter-py

0 comments on commit d21e133

Please sign in to comment.