-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
- Loading branch information
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
# Authentication TL;DR | ||
|
||
Azle canisters can import `ic` from `azle` and use `ic.caller()` to get the [principal (public-key linked identifier)](https://internetcomputer.org/docs/current/references/ic-interface-spec#principal) of the initiator of an HTTP request. HTTP requests are anonymous (principal `2vxsx-fae`) by default, but authentication with web browsers (and maybe Node.js) can be done using a JWT-like API from `azle/http_client`. | ||
|
||
First you import `toJwt` from `azle/http_client`: | ||
|
||
```typescript | ||
import { toJwt } from 'azle/http_client'; | ||
``` | ||
|
||
Then you use `fetch` and construct an `Authorization` header using an [@dfinity/agent](https://www.npmjs.com/package/@dfinity/agent) `Identity`: | ||
|
||
```typescript | ||
const response = await fetch( | ||
`http://bkyz2-fmaaa-aaaaa-qaaaq-cai.localhost:8000/whoami`, | ||
{ | ||
method: 'GET', | ||
headers: [['Authorization', toJwt(this.identity)]] | ||
} | ||
); | ||
``` | ||
|
||
Here's an example of the frontend of a simple web application using `azle/http_client` and [Internet Identity](https://internetcomputer.org/internet-identity): | ||
|
||
```typescript | ||
import { Identity } from '@dfinity/agent'; | ||
import { AuthClient } from '@dfinity/auth-client'; | ||
import { toJwt } from 'azle/http_client'; | ||
import { html, LitElement } from 'lit'; | ||
import { customElement, property } from 'lit/decorators.js'; | ||
|
||
@customElement('azle-app') | ||
export class AzleApp extends LitElement { | ||
@property() | ||
identity: Identity | null = null; | ||
|
||
@property() | ||
whoami: string = ''; | ||
|
||
connectedCallback() { | ||
super.connectedCallback(); | ||
this.authenticate(); | ||
} | ||
|
||
async authenticate() { | ||
const authClient = await AuthClient.create(); | ||
const isAuthenticated = await authClient.isAuthenticated(); | ||
|
||
if (isAuthenticated === true) { | ||
this.handleIsAuthenticated(authClient); | ||
} else { | ||
await this.handleIsNotAuthenticated(authClient); | ||
} | ||
} | ||
|
||
handleIsAuthenticated(authClient: AuthClient) { | ||
this.identity = authClient.getIdentity(); | ||
} | ||
|
||
async handleIsNotAuthenticated(authClient: AuthClient) { | ||
await new Promise((resolve, reject) => { | ||
authClient.login({ | ||
identityProvider: import.meta.env.VITE_IDENTITY_PROVIDER, | ||
onSuccess: resolve as () => void, | ||
onError: reject, | ||
windowOpenerFeatures: `width=500,height=500` | ||
}); | ||
}); | ||
|
||
this.identity = authClient.getIdentity(); | ||
} | ||
|
||
async whoamiUnauthenticated() { | ||
const response = await fetch( | ||
`${import.meta.env.VITE_CANISTER_ORIGIN}/whoami` | ||
); | ||
const responseText = await response.text(); | ||
|
||
this.whoami = responseText; | ||
} | ||
|
||
async whoamiAuthenticated() { | ||
const response = await fetch( | ||
`${import.meta.env.VITE_CANISTER_ORIGIN}/whoami`, | ||
{ | ||
method: 'GET', | ||
headers: [['Authorization', toJwt(this.identity)]] | ||
} | ||
); | ||
const responseText = await response.text(); | ||
|
||
this.whoami = responseText; | ||
} | ||
|
||
render() { | ||
return html` | ||
<h1>Internet Identity</h1> | ||
<h2> | ||
Whoami principal: | ||
<span id="whoamiPrincipal">${this.whoami}</span> | ||
</h2> | ||
<button | ||
id="whoamiUnauthenticated" | ||
@click=${this.whoamiUnauthenticated} | ||
> | ||
Whoami Unauthenticated | ||
</button> | ||
<button | ||
id="whoamiAuthenticated" | ||
@click=${this.whoamiAuthenticated} | ||
.disabled=${this.identity === null} | ||
> | ||
Whoami Authenticated | ||
</button> | ||
`; | ||
} | ||
} | ||
``` | ||
|
||
Here's an example of the backend of that same simple web application: | ||
|
||
```typescript | ||
import { ic } from 'azle'; | ||
import express from 'express'; | ||
|
||
const app = express(); | ||
|
||
app.get('/whoami', (req, res) => { | ||
res.send(ic.caller().toString()); | ||
}); | ||
|
||
app.use(express.static('/dist')); | ||
|
||
app.listen(); | ||
``` | ||
|
||
# Authentication | ||
|
||
Examples: | ||
|
||
- [fetch_ic](https://github.com/demergent-labs/azle/tree/main/examples/fetch_ic) | ||
- [internet_identity](https://github.com/demergent-labs/azle/tree/main/examples/internet_identity) | ||
|
||
## Under-the-hood | ||
|
||
Authentication of ICP calls is done through signatures on messages. [@dfinity/agent](https://www.npmjs.com/package/@dfinity/agent) provides very nice abstractions for creating all of the required signatures in the correct formats when calling into canisters on ICP. Unfortunately this requires you to abandon traditional HTTP requests, as you must use the agent's APIs. | ||
|
||
Azle attempts to enable you to perform traditional HTTP requests with traditional libraries. Currently Azle focuses on `fetch`. When importing `toJwt`, `azle/http_client` will overwrite the global `fetch` function and will intercept `fetch` requests that have `Authorization` headers with an `Identity` as a value. | ||
|
||
Once intercepted, these requests are turned into `@dfinity/agent` requests that call [the http_request and http_request_update canister methods](https://internetcomputer.org/docs/current/references/http-gateway-protocol-spec) directly, thus performing all of the required client-side authentication work. | ||
|
||
We are working to push for ICP to more natively understand JWTs for authentication, without the need to intercept `fetch` requests and convert them into agent requests. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,30 @@ | ||
# Limitations | ||
# Limitations TL;DR | ||
|
||
There are a number of limitations that you are likely to run into while you develop with Azle on ICP. These are generally the most limiting: | ||
|
||
- 5 billion instruction limit for query calls (HTTP GET requests) (~1 second of computation) | ||
- 20 billion instruction limit for update calls (HTTP POST/etc requests) (~5 seconds of computation) | ||
- 2 MiB request size limit | ||
- 3 MiB response size limit | ||
- 4 GiB heap limit | ||
- High request latency relative to traditional web applications (think seconds not milliseconds) | ||
- High costs relative to traditional web applications (think ~10x traditional web costs) | ||
|
||
Read more [here](https://internetcomputer.org/docs/current/developer-docs/smart-contracts/maintain/resource-limits) for in-depth information on current ICP limitations. | ||
|
||
<!-- # Limitations | ||
Keep in mind that this is not an exhaustive collection of the limitations of Azle or [ICP](https://internetcomputer.org/). | ||
Let's discuss some important limitations of Azle and ICP that you are likely to run into: | ||
Let's discuss some important limitations of Azle and ICP that you are likely to run into. This is chapter is currently a work-in-progress: | ||
- `/api` can't be used locally | ||
- instruction limit | ||
- Message size limit | ||
- heap limit | ||
- instruction limit (5 billion) | ||
- Message size limit (2 MiB request, 3 MiB response) | ||
- heap limit (4 GiB) | ||
- http outcalls request and response size, latency, and expense | ||
- 1_000 update calls per sec | ||
- 30_000 query calls per sec | ||
- stable memory limit | ||
- stable memory limit (96 GiB) | ||
- no chunked http responses | ||
- Wasm binary limits | ||
- Wasm binary limits (~10 MiB code section, ~90 MiB data section) --> |