Skip to content

Commit fb7048b

Browse files
Marco SegretogobengoBenjamin Goering
authored
Fix: Ensure actor is correctly authenticated (#19)
Pass the identity to the actor once authenticated This ensures the agent will pass the user's Principal to the backend code once they are authenticated. Co-authored-by: Benjamin Goering <[email protected]> Co-authored-by: Benjamin Goering <[email protected]>
1 parent b0a1b13 commit fb7048b

10 files changed

+195
-94
lines changed

dfx.json

+1-7
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,6 @@
2929
}
3030
},
3131
"networks": {
32-
"ic": {
33-
"providers": [
34-
"https://gw.dfinity.network"
35-
],
36-
"type": "persistent"
37-
},
3832
"alpha": {
3933
"providers": [
4034
"https://mainnet.dfinity.network"
@@ -46,5 +40,5 @@
4640
"type": "ephemeral"
4741
}
4842
},
49-
"dfx": "0.7.0-beta.6"
43+
"dfx": "0.7.0"
5044
}

docs/local-with-internet-identity.md

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Local Development with internet-identity
2+
3+
Follow these steps to run cancan locally along with locally running [dfinity/internet-identity](https://github.com/dfinity/internet-identity) canisters on the same replica.
4+
5+
## Overview
6+
7+
The internet-identity canisters must be running on the same IC replica as the CanCan canisters.
8+
As long as both internet-identity and cancan's `local` network are running on the default port, this is pretty easy.
9+
10+
CanCan must then be accessed in such a way that it uses the local internet-identity canisters to log in instead of the product internet-identity canisters.
11+
12+
## Steps
13+
14+
1. Follow the CanCan [README](../README.md) to start a local replica, deploy CanCan, and opn the app to the sign in screen.
15+
2. Clone the git repo for https://github.com/dfinity/internet-identity to another directory
16+
3. Ensure you have the correct dependencies to build internet-identity (e.g. `[email protected]` at time of this writing)
17+
5. Deploy internet-identity like:
18+
```
19+
II_ENV=development dfx deploy --no-wallet --argument '(null)'
20+
```
21+
* Explanation of command
22+
* `II_ENV=development` is configures internet-identity to know it is running on a development replica.
23+
* `dfx deploy --no-wallet --argument '(null)'` is from the internet-identity README
24+
* When the deploy succeeds, take note of the canister id of internet-identity. You should be able to access internet-identity via a URL like `http://{canisters.internet-identity.id}.localhost:8000/`
25+
6. Access CanCan with URL querystring parameter `internetIdentityUrl` set to the local URL of internet-identity on the local replica, e.g. `http://ryjl3-tyaaa-aaaaa-aaaba-cai.localhost:8000/sign-in?internetIdentityUrl=http://rno2w-sqaaa-aaaaa-aaacq-cai.localhost:8000/`
26+
7. Click 'Authorize' and follow the prompts in the CanCan + internet-identity web pages.

package-lock.json

+45-30
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@
2121
"prepare": "husky install"
2222
},
2323
"dependencies": {
24-
"@dfinity/agent": "^0.8.8",
25-
"@dfinity/auth-client": "^0.8.8",
26-
"@dfinity/authentication": "^0.8.8",
27-
"@dfinity/identity": "^0.8.8",
24+
"@dfinity/agent": "^0.8.9",
25+
"@dfinity/auth-client": "^0.8.9",
26+
"@dfinity/authentication": "^0.8.9",
27+
"@dfinity/identity": "^0.8.9",
2828
"lodash.debounce": "^4.0.8",
2929
"react": "^17.0.1",
3030
"react-dom": "^17.0.1",

src/AppRouter.tsx

+2-8
Original file line numberDiff line numberDiff line change
@@ -25,21 +25,15 @@ function wrapRouteWithFade(Component) {
2525
}
2626

2727
export function AppRouter() {
28-
const {
29-
user,
30-
setUser,
31-
isAuthenticated,
32-
isAuthClientReady,
33-
logOut,
34-
} = useAuth();
28+
const { user, setUser, isAuthenticated, isAuthReady, logOut } = useAuth();
3529

3630
return (
3731
<Router>
3832
<Switch>
3933
{/* Root route, decides whether to redirect someone to feed, signup,
4034
or authorize, based on app state, only when auth client is ready */}
4135
<Route exact path="/">
42-
{isAuthClientReady &&
36+
{isAuthReady &&
4337
(isAuthenticated && user ? (
4438
<Redirect to={{ pathname: "/feed" }} />
4539
) : isAuthenticated ? (

src/components/SignUp.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export function SignUp() {
3232
// with all the user's data. Show a loading message between these async
3333
// backend calls happening.
3434
useEffect(() => {
35-
if (!auth.isAuthClientReady) return;
35+
if (!auth.isAuthReady) return;
3636
if (auth.isAuthenticated && auth.identity !== undefined) {
3737
setIsCheckingICForUser(true);
3838
getUserNameByPrincipal(auth.identity.getPrincipal()).then((username) => {
@@ -50,7 +50,7 @@ export function SignUp() {
5050
}
5151
});
5252
}
53-
}, [auth.isAuthClientReady, auth.isAuthenticated, auth.identity]);
53+
}, [auth.isAuthReady, auth.isAuthenticated, auth.identity]);
5454

5555
// Submit the form to signup with a new username, the backend ensures that
5656
// the username is available.

src/utils/auth.tsx

+16-2
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ import {
66
KEY_LOCALSTORAGE_USER,
77
} from "./index";
88

9+
import { actorController } from "./canister/actor";
910
import { Identity } from "@dfinity/agent";
1011
import { ProfileInfoPlus } from "./canister/typings";
1112

1213
export interface AuthContext {
1314
isAuthenticated: boolean;
14-
isAuthClientReady: boolean;
15+
isAuthReady: boolean;
1516
hasCanCanAccount: boolean;
1617
identity?: Identity;
1718
logIn: () => void;
@@ -108,6 +109,19 @@ export function useProvideAuth(authClient): AuthContext {
108109
}
109110
}, [user]);
110111

112+
useEffect(() => {
113+
if (_identity && !_identity.getPrincipal().isAnonymous()) {
114+
// The auth client isn't ready to make requests until it's completed the
115+
// async authenticate actor method.
116+
setAuthClientReady(false);
117+
actorController.authenticateActor(_identity).then(() => {
118+
setAuthClientReady(true);
119+
});
120+
} else {
121+
actorController.unauthenticateActor();
122+
}
123+
}, [_identity]);
124+
111125
// Just creating variables here so that it's pretty below
112126
const identity = _identity;
113127
const isAuthenticated = isAuthenticatedLocal;
@@ -137,7 +151,7 @@ export function useProvideAuth(authClient): AuthContext {
137151

138152
return {
139153
isAuthenticated,
140-
isAuthClientReady,
154+
isAuthReady: isAuthClientReady && actorController.isReady,
141155
hasCanCanAccount: user !== undefined,
142156
logIn,
143157
logOut,

src/utils/authClient.ts

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1-
import { Identity } from "@dfinity/agent";
2-
import { AuthClient } from "@dfinity/auth-client";
1+
import { Identity } from '@dfinity/agent';
2+
import { AuthClient } from '@dfinity/auth-client';
3+
4+
// Where the IDP should be servied from
5+
const IDENTITY_URL =
6+
new URLSearchParams(document.location.search).get('internetIdentityUrl') ||
7+
process.env.REACT_APP_INTERNET_IDENTITY_URL ||
8+
'https://identity.ic0.app';
39

410
/*
511
* A simple wrapper for the official auth client to initialize it and wrap
@@ -22,6 +28,7 @@ class AuthClientWrapper {
2228
async login(): Promise<Identity | undefined> {
2329
return new Promise(async (resolve) => {
2430
await this.authClient?.login({
31+
identityProvider: IDENTITY_URL,
2532
onSuccess: async () => {
2633
resolve(this.authClient?.getIdentity());
2734
},
@@ -30,7 +37,7 @@ class AuthClientWrapper {
3037
}
3138

3239
async logout() {
33-
return this.authClient?.logout({ returnTo: "/" });
40+
return this.authClient?.logout({ returnTo: '/' });
3441
}
3542

3643
async getIdentity() {

0 commit comments

Comments
 (0)