Read Access Control
In this tutorial, we will cover how to authenticate a user to enforce read access control. This tutorial expands on the schema created in the Write Access Control tutorial.
In Kwil, data is primarily read with view
actions. For executing view
actions, the same general access control rules are available as for write actions. However, because data stored on nodes are default public, Kwil networks running in permissioned or federated environments can use the Kwil Gateway to enforce user authentication and stronger read access control.
Setting view action privacy is done using the Kwil Gateway. The gateway is still in private beta. If you would like access, please contact our team.
Overview
The Kwil Gateway requires a user to sign a message with their account keys. Once the signature is verified, the gateway will return the user a cookie to be passed with all subsequent requests.
Require Authentication in Kuneiform
To signal to the Kwil Gateway that an action requires authentication, add an annotation before the action. The @kgw(authn='true')
annotation will require the user to authenticate via a signature before executing the action.
// authentication required view action to reveal a user profile
@kgw(authn='true')
action get_profile () public view {
SELECT *
FROM users
WHERE address = @caller;
}
The @kgw(authn='true')
annotation will only require the user to authenticate IF the Kwil Gateway is enabled. If the gateway is not enabled, the annotation will be ignored.
Authenticating a User
Using the JavaScript SDK and the KwilSigner, a user can authenticate with the Kwil Gateway. When calling the call
method, the Kwil SDK will check if the gateway is enforcing authentication. If authentication is enforced, the gateway will prompt the user to sign a message with their account keys. Once the signature is verified, the SDK will include a cookie to be passed with all subsequent requests.
- Browser
- NodeJs
import { WebKwil, KwilSigner } from '@kwilteam/kwil-js';
import { BrowserProvider } from 'ethers';
const kwil = new WebKwil({
kwilProvider: "https://longhorn.kwil.com",
chainId: "longhorn",
});
async function getSigner() {
const provider = new BrowserProvider(window.ethereum);
const ethSigner = await provider.getSigner();
const ethAddress = await ethSigner.getAddress();
return new KwilSigner(ethSigner, ethAddress);
}
async function authenticatedAction() {
const kwilSigner = await getSigner();
const payload = {
action: "get_profile",
dbid: 'x123abc...'
}
return await kwil.call(payload, kwilSigner); // user will be prompted to authenticate
}
import { NodeKwil } from '@kwilteam/kwil-js';
const kwil = new NodeKwil({
kwilProvider: "https://longhorn.kwil.com",
chainId: "longhorn",
});
async function getSigner() {
const provider = new BrowserProvider(window.ethereum);
const ethSigner = await provider.getSigner();
const ethAddress = await ethSigner.getAddress();
return new KwilSigner(ethSigner, ethAddress);
}
async function authenticatedAction() {
const kwilSigner = await getSigner();
const payload = {
action: "get_profile",
dbid: 'x123abc...'
}
return await kwil.call(payload, kwilSigner); // user will be prompted to authenticate
}
Logging Out a User
Before using a new signer, it is important to log out the current user. This will clear the cookie and prompt the new user to sign a new message.
async function logout() {
await kwil.auth.logout();
}
Advanced Usage
Disable Auto Authentication
By default, the Kwil SDK will automatically prompt the user to authenticate when calling an action that requires authentication. To disable this behavior, set the autoAuthenticate
option to false
.
const kwil = new WebKwil({
kwilProvider: "https://longhorn.kwil.com",
chainId: "longhorn",
autoAuthenticate: false,
});
Manually Authenticate
To manually authenticate a user, call the authenticate
method. Kwil-JS will automatically include the cookie with all subsequent requests.
async function manualAuthenticate() {
await kwil.auth.authenticate(kwilSigner);
}
NodeJS: Manually Pass Cookie
In NodeJS, you can optionally set the cookie manually. This is useful when you want to implement additional logic around the authentication process.
You should not pass the cookie if in browser (WebKwil). The SDK relies on the browser's cookie jar to store the cookie.
async function authenticatedAction() {
const auth = await kwil.auth.authenticate(kwilSigner);
const cookie = auth.data?.cookie;
const payload = {
action: "get_profile",
dbid: 'x123abc...',
cookie
}
return await kwil.call(payload); // user will not be prompted to authenticate
}