@iaurelius/accounts-expo 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +78 -0
- package/dist/core.d.ts +62 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +206 -0
- package/dist/core.js.map +1 -0
- package/dist/expo.d.ts +13 -0
- package/dist/expo.d.ts.map +1 -0
- package/dist/expo.js +31 -0
- package/dist/expo.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/react.d.ts +47 -0
- package/dist/react.d.ts.map +1 -0
- package/dist/react.js +49 -0
- package/dist/react.js.map +1 -0
- package/package.json +53 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 iAurelius
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# @iaurelius/accounts-expo
|
|
2
|
+
|
|
3
|
+
Accounts by iAurelius for Expo (iOS, Android and web).
|
|
4
|
+
|
|
5
|
+
People sign in on your application's hosted page, with passkeys, email codes and Google. The page opens in the system's authentication session: `ASWebAuthenticationSession` on iOS, Custom Tabs on Android. The SDK then:
|
|
6
|
+
- keeps the tokens in SecureStore;
|
|
7
|
+
- refreshes the access token when it is about to expire;
|
|
8
|
+
- signs out here and on the hosted pages.
|
|
9
|
+
|
|
10
|
+
## Quick start
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
npx @iaurelius/accounts init --code aci_… # the command from the console: Apps and APIs → Integrate your app
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
What it does:
|
|
17
|
+
- registers your mobile app with its bundle id as the scheme (`com.example.app:/oauth/callback`, RFC 8252);
|
|
18
|
+
- installs this package and its Expo modules with `npx expo install`;
|
|
19
|
+
- writes `.env.local`;
|
|
20
|
+
- adds the scheme to `app.json`.
|
|
21
|
+
|
|
22
|
+
Rebuild the app afterwards, because the scheme is native. By hand, the steps are:
|
|
23
|
+
|
|
24
|
+
```sh
|
|
25
|
+
npx expo install @iaurelius/accounts-expo expo-crypto expo-secure-store expo-web-browser
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
// app/_layout.tsx
|
|
30
|
+
import { AccountsProvider } from "@iaurelius/accounts-expo";
|
|
31
|
+
import { Stack } from "expo-router";
|
|
32
|
+
|
|
33
|
+
export default function RootLayout() {
|
|
34
|
+
return (
|
|
35
|
+
<AccountsProvider
|
|
36
|
+
publishableKey={process.env.EXPO_PUBLIC_ACCOUNTS_PUBLISHABLE_KEY!}
|
|
37
|
+
clientId={process.env.EXPO_PUBLIC_ACCOUNTS_CLIENT_ID!}
|
|
38
|
+
scheme="com.example.app"
|
|
39
|
+
>
|
|
40
|
+
<Stack />
|
|
41
|
+
</AccountsProvider>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
import { SignedIn, SignedOut, useAuth, useUser } from "@iaurelius/accounts-expo";
|
|
48
|
+
import { Button, Text } from "react-native";
|
|
49
|
+
|
|
50
|
+
function Profile() {
|
|
51
|
+
const { signIn, signOut, getToken } = useAuth();
|
|
52
|
+
const { user } = useUser();
|
|
53
|
+
return (
|
|
54
|
+
<>
|
|
55
|
+
<SignedOut><Button title="Sign in" onPress={signIn} /></SignedOut>
|
|
56
|
+
<SignedIn>
|
|
57
|
+
<Text>{user?.email}</Text>
|
|
58
|
+
<Button title="Call my API" onPress={async () => fetch("https://api.example.com/me", { headers: { authorization: `Bearer ${await getToken()}` } })} />
|
|
59
|
+
<Button title="Sign out" onPress={() => signOut()} />
|
|
60
|
+
</SignedIn>
|
|
61
|
+
</>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
On the web, add the route `app/oauth/callback.tsx`, which calls `completeSignIn()` from this package.
|
|
67
|
+
|
|
68
|
+
## Security
|
|
69
|
+
|
|
70
|
+
- **Sign-in:** authorization code with PKCE (S256), `state` and `nonce`, and RFC 9207's `iss` checked. The app is public, with no secret on the device.
|
|
71
|
+
- **ID token:** it comes straight from the token endpoint over TLS, so its issuer, audience, nonce and expiry are checked (OIDC Core 3.1.3.7).
|
|
72
|
+
- **On the device:** tokens stay in SecureStore, split in parts because Android is unreliable past 2 KB.
|
|
73
|
+
- **Revocation:** a person who is banned or signed out everywhere is out at the next refresh. Sign-out revokes the refresh token.
|
|
74
|
+
- **Bundle size:** the package uses no Node APIs and no WebCrypto (`expo-crypto` instead), and does not pull jose into your bundle.
|
|
75
|
+
|
|
76
|
+
## License
|
|
77
|
+
|
|
78
|
+
MIT
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type FetchLike, type SessionUser } from "@iaurelius/accounts/oidc";
|
|
2
|
+
export type { SessionUser };
|
|
3
|
+
export type Storage = {
|
|
4
|
+
get(key: string): Promise<string | null>;
|
|
5
|
+
set(key: string, value: string): Promise<void>;
|
|
6
|
+
remove(key: string): Promise<void>;
|
|
7
|
+
};
|
|
8
|
+
export type AuthSessionResult = {
|
|
9
|
+
type: "success";
|
|
10
|
+
url: string;
|
|
11
|
+
} | {
|
|
12
|
+
type: "cancel" | "dismiss" | "opened" | "locked";
|
|
13
|
+
};
|
|
14
|
+
export type Browser = {
|
|
15
|
+
openAuthSession(url: string, redirectUri: string): Promise<AuthSessionResult>;
|
|
16
|
+
};
|
|
17
|
+
export type Crypto = {
|
|
18
|
+
randomString(bytes: number): string;
|
|
19
|
+
sha256Base64Url(input: string): Promise<string>;
|
|
20
|
+
};
|
|
21
|
+
export type AccountsState = {
|
|
22
|
+
isLoaded: boolean;
|
|
23
|
+
isSignedIn: boolean;
|
|
24
|
+
user: SessionUser | null;
|
|
25
|
+
sessionId: string | null;
|
|
26
|
+
};
|
|
27
|
+
export type ClientOptions = {
|
|
28
|
+
publishableKey: string;
|
|
29
|
+
clientId: string;
|
|
30
|
+
/** Where the hosted page sends the person back: the app's scheme (com.example.app:/oauth/callback) or, on the web, its origin. */
|
|
31
|
+
redirectUri: string;
|
|
32
|
+
/** Your API's identifier: getToken() gives tokens for it. */
|
|
33
|
+
audience?: string;
|
|
34
|
+
storage: Storage;
|
|
35
|
+
browser: Browser;
|
|
36
|
+
crypto: Crypto;
|
|
37
|
+
fetch?: FetchLike;
|
|
38
|
+
/** Refresh when the access token has less than this left (default 60 s). */
|
|
39
|
+
refreshBeforeSeconds?: number;
|
|
40
|
+
};
|
|
41
|
+
/** A store that splits big values (SecureStore is unreliable past ~2 KB on Android): key.n holds the count. */
|
|
42
|
+
export declare function chunked(storage: Storage, size?: number): Storage;
|
|
43
|
+
/** The query of a redirect URL, by hand: React Native's URL does not parse custom schemes reliably. */
|
|
44
|
+
export declare function queryOf(url: string): Record<string, string>;
|
|
45
|
+
export declare function createAccountsClient(o: ClientOptions): {
|
|
46
|
+
readonly state: AccountsState;
|
|
47
|
+
subscribe(l: (s: AccountsState) => void): () => void;
|
|
48
|
+
/** The session kept on the device, refreshed if needed. */
|
|
49
|
+
load(): Promise<AccountsState>;
|
|
50
|
+
/** Opens the hosted page; resolves once the person is back (signed in, or unchanged if they closed it). */
|
|
51
|
+
signIn: () => Promise<AccountsState>;
|
|
52
|
+
/** The same, on "create an account". */
|
|
53
|
+
signUp: () => Promise<AccountsState>;
|
|
54
|
+
/** An access token for your API, refreshed if it is about to expire; null when signed out. */
|
|
55
|
+
getToken(): Promise<string | null>;
|
|
56
|
+
/** Out here (the refresh token revoked) and, unless told otherwise, on the hosted pages too. */
|
|
57
|
+
signOut(opts?: {
|
|
58
|
+
endSession?: boolean;
|
|
59
|
+
}): Promise<void>;
|
|
60
|
+
};
|
|
61
|
+
export type AccountsClient = ReturnType<typeof createAccountsClient>;
|
|
62
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AAIA,OAAO,EAWL,KAAK,SAAS,EACd,KAAK,WAAW,EACjB,MAAM,0BAA0B,CAAC;AAElC,YAAY,EAAE,WAAW,EAAE,CAAC;AAE5B,MAAM,MAAM,OAAO,GAAG;IAAE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAAC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAAC,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,CAAC;AACvJ,MAAM,MAAM,iBAAiB,GAAG;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,CAAA;CAAE,CAAC;AACxH,MAAM,MAAM,OAAO,GAAG;IAAE,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAA;CAAE,CAAC;AACxG,MAAM,MAAM,MAAM,GAAG;IAAE,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAAC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;CAAE,CAAC;AAE9G,MAAM,MAAM,aAAa,GAAG;IAAE,QAAQ,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAI3H,MAAM,MAAM,aAAa,GAAG;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,kIAAkI;IAClI,WAAW,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,4EAA4E;IAC5E,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAIF,+GAA+G;AAC/G,wBAAgB,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,SAAO,GAAG,OAAO,CAqB9D;AAED,uGAAuG;AACvG,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAU3D;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,aAAa;aAoG7C,KAAK;IAGT,SAAS,IAAI,CAAC,CAAC,EAAE,aAAa,KAAK,IAAI;IAMvC,2DAA2D;IACrD,IAAI;IAaV,2GAA2G;IAC3G,MAAM;IACN,wCAAwC;IACxC,MAAM;IACN,8FAA8F;IACxF,QAAQ;IAGd,gGAAgG;IAC1F,OAAO,QAAO;QAAE,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE;EAQ/C;AAED,MAAM,MAAM,cAAc,GAAG,UAAU,CAAC,OAAO,oBAAoB,CAAC,CAAC"}
|
package/dist/core.js
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// The Expo SDK's logic, without Expo: sign-in on the hosted page in an authentication session (PKCE
|
|
2
|
+
// S256, state, nonce, RFC 9207's iss), the session kept in a secure store, an access token that refreshes
|
|
3
|
+
// itself, and sign-out. The platform's parts (store, browser, crypto) are passed in: src/expo.ts gives
|
|
4
|
+
// Expo's; the tests give Node's and the platform's own server.
|
|
5
|
+
import { OAuthError, authorizationUrl, endSessionUrl, exchangeCode, fetchUserInfo, issuerFromPublishableKey, readIdToken, refreshTokens, revokeToken, userFromClaims, } from "@iaurelius/accounts/oidc";
|
|
6
|
+
const now = () => Math.floor(Date.now() / 1000);
|
|
7
|
+
/** A store that splits big values (SecureStore is unreliable past ~2 KB on Android): key.n holds the count. */
|
|
8
|
+
export function chunked(storage, size = 1800) {
|
|
9
|
+
return {
|
|
10
|
+
async get(key) {
|
|
11
|
+
const n = Number(await storage.get(`${key}.n`));
|
|
12
|
+
if (!Number.isInteger(n) || n < 1)
|
|
13
|
+
return null;
|
|
14
|
+
const parts = await Promise.all(Array.from({ length: n }, (_, i) => storage.get(`${key}.${i}`)));
|
|
15
|
+
return parts.some((p) => p === null) ? null : parts.join("");
|
|
16
|
+
},
|
|
17
|
+
async set(key, value) {
|
|
18
|
+
const old = Number(await storage.get(`${key}.n`)) || 0;
|
|
19
|
+
const parts = Array.from({ length: Math.max(1, Math.ceil(value.length / size)) }, (_, i) => value.slice(i * size, (i + 1) * size));
|
|
20
|
+
for (const [i, p] of parts.entries())
|
|
21
|
+
await storage.set(`${key}.${i}`, p);
|
|
22
|
+
await storage.set(`${key}.n`, String(parts.length));
|
|
23
|
+
for (let i = parts.length; i < old; i++)
|
|
24
|
+
await storage.remove(`${key}.${i}`);
|
|
25
|
+
},
|
|
26
|
+
async remove(key) {
|
|
27
|
+
const n = Number(await storage.get(`${key}.n`)) || 0;
|
|
28
|
+
await storage.remove(`${key}.n`);
|
|
29
|
+
for (let i = 0; i < n; i++)
|
|
30
|
+
await storage.remove(`${key}.${i}`);
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/** The query of a redirect URL, by hand: React Native's URL does not parse custom schemes reliably. */
|
|
35
|
+
export function queryOf(url) {
|
|
36
|
+
const q = url.split("#")[0].split("?")[1] ?? "";
|
|
37
|
+
const out = {};
|
|
38
|
+
for (const pair of q.split("&")) {
|
|
39
|
+
if (!pair)
|
|
40
|
+
continue;
|
|
41
|
+
const i = pair.indexOf("=");
|
|
42
|
+
const k = decodeURIComponent((i < 0 ? pair : pair.slice(0, i)).replace(/\+/g, " "));
|
|
43
|
+
if (!(k in out))
|
|
44
|
+
out[k] = i < 0 ? "" : decodeURIComponent(pair.slice(i + 1).replace(/\+/g, " "));
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
export function createAccountsClient(o) {
|
|
49
|
+
const issuer = issuerFromPublishableKey(o.publishableKey);
|
|
50
|
+
const creds = { issuer, clientId: o.clientId, fetch: o.fetch };
|
|
51
|
+
const store = chunked(o.storage);
|
|
52
|
+
const key = `accounts.${o.clientId.replace(/[^A-Za-z0-9._-]/g, "_")}`;
|
|
53
|
+
let session = null;
|
|
54
|
+
let state = { isLoaded: false, isSignedIn: false, user: null, sessionId: null };
|
|
55
|
+
const listeners = new Set();
|
|
56
|
+
function publish(loaded = true) {
|
|
57
|
+
let user = null;
|
|
58
|
+
let sid = null;
|
|
59
|
+
if (session) {
|
|
60
|
+
const c = readIdToken(session.it);
|
|
61
|
+
user = userFromClaims({ ...c, ...session.u, sub: c.sub });
|
|
62
|
+
sid = typeof c.sid === "string" ? c.sid : null;
|
|
63
|
+
}
|
|
64
|
+
state = { isLoaded: loaded, isSignedIn: !!session, user, sessionId: sid };
|
|
65
|
+
for (const l of listeners)
|
|
66
|
+
l(state);
|
|
67
|
+
}
|
|
68
|
+
async function save(s) {
|
|
69
|
+
session = s;
|
|
70
|
+
if (s)
|
|
71
|
+
await store.set(key, JSON.stringify(s));
|
|
72
|
+
else
|
|
73
|
+
await store.remove(key);
|
|
74
|
+
publish();
|
|
75
|
+
}
|
|
76
|
+
async function profile(accessToken) {
|
|
77
|
+
const c = await fetchUserInfo({ issuer, accessToken, fetch: o.fetch });
|
|
78
|
+
if (!c)
|
|
79
|
+
return undefined;
|
|
80
|
+
const p = {};
|
|
81
|
+
if (typeof c.email === "string")
|
|
82
|
+
p.email = c.email;
|
|
83
|
+
if (typeof c.email_verified === "boolean")
|
|
84
|
+
p.email_verified = c.email_verified;
|
|
85
|
+
if (typeof c.name === "string" && c.name)
|
|
86
|
+
p.name = c.name;
|
|
87
|
+
if (typeof c.picture === "string" && c.picture)
|
|
88
|
+
p.picture = c.picture;
|
|
89
|
+
return p;
|
|
90
|
+
}
|
|
91
|
+
// One refresh at a time: two screens asking for a token at once share it (the refresh token rotates).
|
|
92
|
+
let refreshing = null;
|
|
93
|
+
async function fresh() {
|
|
94
|
+
const s = session;
|
|
95
|
+
if (!s)
|
|
96
|
+
return null;
|
|
97
|
+
if (s.exp - now() > (o.refreshBeforeSeconds ?? 60))
|
|
98
|
+
return s;
|
|
99
|
+
if (!s.rt) {
|
|
100
|
+
if (s.exp > now())
|
|
101
|
+
return s;
|
|
102
|
+
await save(null);
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
refreshing ??= (async () => {
|
|
106
|
+
try {
|
|
107
|
+
const t = await refreshTokens(creds, { refreshToken: s.rt, resource: o.audience });
|
|
108
|
+
const next = { at: t.accessToken, rt: t.refreshToken ?? s.rt, it: t.idToken ?? s.it, exp: t.expiresAt, u: (await profile(t.accessToken)) ?? s.u };
|
|
109
|
+
await save(next);
|
|
110
|
+
return next;
|
|
111
|
+
}
|
|
112
|
+
catch (e) {
|
|
113
|
+
// Refused (revoked, banned, session over): out. Unreachable: the token while it lasts.
|
|
114
|
+
if (e instanceof OAuthError && e.status >= 400 && e.status < 500) {
|
|
115
|
+
await save(null);
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
return s.exp > now() ? s : null;
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
refreshing = null;
|
|
122
|
+
}
|
|
123
|
+
})();
|
|
124
|
+
return refreshing;
|
|
125
|
+
}
|
|
126
|
+
/** The ID token straight from the token endpoint over TLS (OIDC Core 3.1.3.7): its claims are checked. */
|
|
127
|
+
function checkIdToken(token, nonce) {
|
|
128
|
+
const c = readIdToken(token);
|
|
129
|
+
const aud = Array.isArray(c.aud) ? c.aud : [c.aud];
|
|
130
|
+
if (c.iss !== issuer || !aud.includes(o.clientId) || c.nonce !== nonce || typeof c.exp !== "number" || c.exp < now() - 5 || typeof c.sub !== "string")
|
|
131
|
+
throw new OAuthError("invalid_id_token", "The ID token is not for this sign-in.");
|
|
132
|
+
}
|
|
133
|
+
async function signIn(prompt) {
|
|
134
|
+
const verifier = o.crypto.randomString(32);
|
|
135
|
+
const challenge = await o.crypto.sha256Base64Url(verifier);
|
|
136
|
+
const expected = o.crypto.randomString(24);
|
|
137
|
+
const nonce = o.crypto.randomString(24);
|
|
138
|
+
const url = authorizationUrl({ issuer, clientId: o.clientId, redirectUri: o.redirectUri, state: expected, nonce, codeChallenge: challenge, resource: o.audience, prompt });
|
|
139
|
+
const r = await o.browser.openAuthSession(url, o.redirectUri);
|
|
140
|
+
if (r.type !== "success")
|
|
141
|
+
return state; // closed: nothing changes
|
|
142
|
+
const q = queryOf(r.url);
|
|
143
|
+
if (q.state !== expected)
|
|
144
|
+
throw new OAuthError("invalid_state", "The answer does not belong to this sign-in.");
|
|
145
|
+
if (q.error) {
|
|
146
|
+
if (q.error === "access_denied")
|
|
147
|
+
return state;
|
|
148
|
+
throw new OAuthError(q.error, q.error_description);
|
|
149
|
+
}
|
|
150
|
+
if (q.iss !== issuer)
|
|
151
|
+
throw new OAuthError("invalid_issuer", "The answer did not come from this app's sign-in.");
|
|
152
|
+
if (!q.code)
|
|
153
|
+
throw new OAuthError("invalid_request", "The answer has no code.");
|
|
154
|
+
const t = await exchangeCode(creds, { code: q.code, redirectUri: o.redirectUri, codeVerifier: verifier, resource: o.audience });
|
|
155
|
+
if (!t.idToken)
|
|
156
|
+
throw new OAuthError("invalid_response", "No ID token: the app needs the openid scope.");
|
|
157
|
+
checkIdToken(t.idToken, nonce);
|
|
158
|
+
await save({ at: t.accessToken, rt: t.refreshToken, it: t.idToken, exp: t.expiresAt, u: await profile(t.accessToken) });
|
|
159
|
+
return state;
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
get state() {
|
|
163
|
+
return state;
|
|
164
|
+
},
|
|
165
|
+
subscribe(l) {
|
|
166
|
+
listeners.add(l);
|
|
167
|
+
return () => {
|
|
168
|
+
listeners.delete(l);
|
|
169
|
+
};
|
|
170
|
+
},
|
|
171
|
+
/** The session kept on the device, refreshed if needed. */
|
|
172
|
+
async load() {
|
|
173
|
+
try {
|
|
174
|
+
const raw = await store.get(key);
|
|
175
|
+
const s = raw ? JSON.parse(raw) : null;
|
|
176
|
+
session = s && typeof s.at === "string" && typeof s.it === "string" && typeof s.exp === "number" ? s : null;
|
|
177
|
+
if (session)
|
|
178
|
+
readIdToken(session.it);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
session = null;
|
|
182
|
+
}
|
|
183
|
+
await fresh();
|
|
184
|
+
publish();
|
|
185
|
+
return state;
|
|
186
|
+
},
|
|
187
|
+
/** Opens the hosted page; resolves once the person is back (signed in, or unchanged if they closed it). */
|
|
188
|
+
signIn: () => signIn(),
|
|
189
|
+
/** The same, on "create an account". */
|
|
190
|
+
signUp: () => signIn("create"),
|
|
191
|
+
/** An access token for your API, refreshed if it is about to expire; null when signed out. */
|
|
192
|
+
async getToken() {
|
|
193
|
+
return (await fresh())?.at ?? null;
|
|
194
|
+
},
|
|
195
|
+
/** Out here (the refresh token revoked) and, unless told otherwise, on the hosted pages too. */
|
|
196
|
+
async signOut(opts = {}) {
|
|
197
|
+
const s = session;
|
|
198
|
+
await save(null);
|
|
199
|
+
if (s?.rt)
|
|
200
|
+
await revokeToken(creds, { token: s.rt, hint: "refresh_token" });
|
|
201
|
+
if (s && opts.endSession !== false)
|
|
202
|
+
await o.browser.openAuthSession(endSessionUrl({ issuer, clientId: o.clientId, idTokenHint: s.it, postLogoutRedirectUri: o.redirectUri }), o.redirectUri).catch(() => undefined);
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=core.js.map
|
package/dist/core.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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"}
|
package/dist/expo.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Browser, Crypto, Storage } from "./core.js";
|
|
2
|
+
export declare const secureStorage: Storage;
|
|
3
|
+
/** ephemeral: no cookies shared with the system browser (each sign-in starts from scratch). */
|
|
4
|
+
export declare const authSessionBrowser: (ephemeral?: boolean) => Browser;
|
|
5
|
+
export declare const expoCrypto: Crypto;
|
|
6
|
+
/** Where the hosted page sends people back: the app's own scheme, or the web page's origin. */
|
|
7
|
+
export declare function redirectUriFor(scheme: string | undefined): string;
|
|
8
|
+
/** On the web, the page at /oauth/callback calls this to hand the answer back to the page that opened the sign-in. */
|
|
9
|
+
export declare const completeSignIn: () => {
|
|
10
|
+
type: "success" | "failed";
|
|
11
|
+
message: string;
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=expo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expo.d.ts","sourceRoot":"","sources":["../src/expo.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1D,eAAO,MAAM,aAAa,EAAE,OAI3B,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,kBAAkB,2BAAwB,OAErD,CAAC;AAGH,eAAO,MAAM,UAAU,EAAE,MAGxB,CAAC;AAEF,+FAA+F;AAC/F,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,UAKxD;AAED,sHAAsH;AACtH,eAAO,MAAM,cAAc;;;CAA8C,CAAC"}
|
package/dist/expo.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// Expo's parts for the client (src/core.ts): SecureStore, the authentication session of expo-web-browser
|
|
2
|
+
// (ASWebAuthenticationSession on iOS, Custom Tabs on Android, a popup on the web) and expo-crypto.
|
|
3
|
+
import * as ExpoCrypto from "expo-crypto";
|
|
4
|
+
import * as SecureStore from "expo-secure-store";
|
|
5
|
+
import * as WebBrowser from "expo-web-browser";
|
|
6
|
+
export const secureStorage = {
|
|
7
|
+
get: (k) => SecureStore.getItemAsync(k),
|
|
8
|
+
set: (k, v) => SecureStore.setItemAsync(k, v),
|
|
9
|
+
remove: (k) => SecureStore.deleteItemAsync(k),
|
|
10
|
+
};
|
|
11
|
+
/** ephemeral: no cookies shared with the system browser (each sign-in starts from scratch). */
|
|
12
|
+
export const authSessionBrowser = (ephemeral = false) => ({
|
|
13
|
+
openAuthSession: (url, redirectUri) => WebBrowser.openAuthSessionAsync(url, redirectUri, { preferEphemeralSession: ephemeral }),
|
|
14
|
+
});
|
|
15
|
+
const b64url = (b64) => b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
16
|
+
export const expoCrypto = {
|
|
17
|
+
randomString: (bytes) => b64url(btoa(String.fromCharCode(...ExpoCrypto.getRandomBytes(bytes)))),
|
|
18
|
+
sha256Base64Url: async (input) => b64url(await ExpoCrypto.digestStringAsync(ExpoCrypto.CryptoDigestAlgorithm.SHA256, input, { encoding: ExpoCrypto.CryptoEncoding.BASE64 })),
|
|
19
|
+
};
|
|
20
|
+
/** Where the hosted page sends people back: the app's own scheme, or the web page's origin. */
|
|
21
|
+
export function redirectUriFor(scheme) {
|
|
22
|
+
const g = globalThis;
|
|
23
|
+
if (typeof g.document !== "undefined" && g.location)
|
|
24
|
+
return `${g.location.origin}/oauth/callback`;
|
|
25
|
+
if (!scheme)
|
|
26
|
+
throw new Error("Pass scheme to <AccountsProvider> (your app's bundle id, such as com.example.app): the hosted page sends people back to com.example.app:/oauth/callback.");
|
|
27
|
+
return `${scheme}:/oauth/callback`;
|
|
28
|
+
}
|
|
29
|
+
/** On the web, the page at /oauth/callback calls this to hand the answer back to the page that opened the sign-in. */
|
|
30
|
+
export const completeSignIn = () => WebBrowser.maybeCompleteAuthSession();
|
|
31
|
+
//# sourceMappingURL=expo.js.map
|
package/dist/expo.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expo.js","sourceRoot":"","sources":["../src/expo.ts"],"names":[],"mappings":"AAAA,yGAAyG;AACzG,mGAAmG;AACnG,OAAO,KAAK,UAAU,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,WAAW,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,UAAU,MAAM,kBAAkB,CAAC;AAG/C,MAAM,CAAC,MAAM,aAAa,GAAY;IACpC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,CAAC;IACvC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC;IAC7C,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC,CAAC;CAC9C,CAAC;AAEF,+FAA+F;AAC/F,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,SAAS,GAAG,KAAK,EAAW,EAAE,CAAC,CAAC;IACjE,eAAe,EAAE,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,CAAC,UAAU,CAAC,oBAAoB,CAAC,GAAG,EAAE,WAAW,EAAE,EAAE,sBAAsB,EAAE,SAAS,EAAE,CAAC;CAChI,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC/F,MAAM,CAAC,MAAM,UAAU,GAAW;IAChC,YAAY,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,UAAU,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC/F,eAAe,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,UAAU,CAAC,iBAAiB,CAAC,UAAU,CAAC,qBAAqB,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC;CAC7K,CAAC;AAEF,+FAA+F;AAC/F,MAAM,UAAU,cAAc,CAAC,MAA0B;IACvD,MAAM,CAAC,GAAG,UAAmE,CAAC;IAC9E,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,WAAW,IAAI,CAAC,CAAC,QAAQ;QAAE,OAAO,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,iBAAiB,CAAC;IAClG,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,0JAA0J,CAAC,CAAC;IACzL,OAAO,GAAG,MAAM,kBAAkB,CAAC;AACrC,CAAC;AAED,sHAAsH;AACtH,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,wBAAwB,EAAE,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { completeSignIn } from "./expo.js";
|
|
2
|
+
export declare const AccountsProvider: ({ children, publishableKey, clientId, scheme, audience, ephemeral }: import("./react.js").AccountsProviderProps) => import("react").JSX.Element;
|
|
3
|
+
export { SignedIn, SignedOut, useAuth, useUser, type AccountsProviderProps } from "./react.js";
|
|
4
|
+
export { completeSignIn };
|
|
5
|
+
export type { AccountsState, SessionUser } from "./core.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,cAAc,EAA6C,MAAM,WAAW,CAAC;AAG1G,eAAO,MAAM,gBAAgB,kJAA4G,CAAC;AAC1I,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAC/F,OAAO,EAAE,cAAc,EAAE,CAAC;AAC1B,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// @iaurelius/accounts-expo: the provider with Expo's parts, the hooks and the components.
|
|
2
|
+
import { authSessionBrowser, completeSignIn, expoCrypto, redirectUriFor, secureStorage } from "./expo.js";
|
|
3
|
+
import { makeProvider } from "./react.js";
|
|
4
|
+
export const AccountsProvider = makeProvider({ storage: secureStorage, browser: authSessionBrowser, crypto: expoCrypto, redirectUriFor });
|
|
5
|
+
export { SignedIn, SignedOut, useAuth, useUser } from "./react.js";
|
|
6
|
+
export { completeSignIn };
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0FAA0F;AAC1F,OAAO,EAAE,kBAAkB,EAAE,cAAc,EAAE,UAAU,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1G,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,CAAC,MAAM,gBAAgB,GAAG,YAAY,CAAC,EAAE,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,kBAAkB,EAAE,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC,CAAC;AAC1I,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAA8B,MAAM,YAAY,CAAC;AAC/F,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
package/dist/react.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { type AccountsState, type Browser, type Crypto, type Storage } from "./core.js";
|
|
3
|
+
export type AccountsProviderProps = {
|
|
4
|
+
children?: ReactNode;
|
|
5
|
+
/** pk_live_… (write it as process.env.EXPO_PUBLIC_ACCOUNTS_PUBLISHABLE_KEY: Expo inlines it in your app's code). */
|
|
6
|
+
publishableKey: string;
|
|
7
|
+
/** Your mobile app's client id, from the console (Apps and APIs). */
|
|
8
|
+
clientId: string;
|
|
9
|
+
/** Your app's reverse-domain scheme, its bundle id (com.example.app). */
|
|
10
|
+
scheme?: string;
|
|
11
|
+
/** Your API's identifier: getToken() gives tokens for it. */
|
|
12
|
+
audience?: string;
|
|
13
|
+
/** No cookies shared with the system browser. Default false: signing in again is one tap. */
|
|
14
|
+
ephemeral?: boolean;
|
|
15
|
+
};
|
|
16
|
+
/** The platform's parts, given by the entry (src/index.tsx: Expo's) or by tests. */
|
|
17
|
+
export type Platform = {
|
|
18
|
+
storage: Storage;
|
|
19
|
+
browser: (ephemeral: boolean) => Browser;
|
|
20
|
+
crypto: Crypto;
|
|
21
|
+
redirectUriFor: (scheme?: string) => string;
|
|
22
|
+
};
|
|
23
|
+
export declare function makeProvider(platform: Platform): ({ children, publishableKey, clientId, scheme, audience, ephemeral }: AccountsProviderProps) => import("react").JSX.Element;
|
|
24
|
+
export declare function useAuth(): {
|
|
25
|
+
isLoaded: boolean;
|
|
26
|
+
isSignedIn: boolean;
|
|
27
|
+
userId: string | null;
|
|
28
|
+
sessionId: string | null;
|
|
29
|
+
getToken: () => Promise<string | null>;
|
|
30
|
+
signIn: () => Promise<AccountsState>;
|
|
31
|
+
signUp: () => Promise<AccountsState>;
|
|
32
|
+
signOut: (opts?: {
|
|
33
|
+
endSession?: boolean;
|
|
34
|
+
}) => Promise<void>;
|
|
35
|
+
};
|
|
36
|
+
export declare function useUser(): {
|
|
37
|
+
isLoaded: boolean;
|
|
38
|
+
isSignedIn: boolean;
|
|
39
|
+
user: import("@iaurelius/accounts/oidc").SessionUser | null;
|
|
40
|
+
};
|
|
41
|
+
export declare function SignedIn({ children }: {
|
|
42
|
+
children?: ReactNode;
|
|
43
|
+
}): import("react").JSX.Element | null;
|
|
44
|
+
export declare function SignedOut({ children }: {
|
|
45
|
+
children?: ReactNode;
|
|
46
|
+
}): import("react").JSX.Element | null;
|
|
47
|
+
//# sourceMappingURL=react.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"AACA,OAAO,EAA2D,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAChG,OAAO,EAA6C,KAAK,aAAa,EAAE,KAAK,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,OAAO,EAAE,MAAM,WAAW,CAAC;AAInI,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,oHAAoH;IACpH,cAAc,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,QAAQ,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6FAA6F;IAC7F,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,oFAAoF;AACpF,MAAM,MAAM,QAAQ,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,MAAM,CAAA;CAAE,CAAC;AAEnJ,wBAAgB,YAAY,CAAC,QAAQ,EAAE,QAAQ,yEACiE,qBAAqB,iCAapI;AAQD,wBAAgB,OAAO;IAGnB,QAAQ;IACR,UAAU;IACV,MAAM;IACN,SAAS;IACT,QAAQ;IACR,MAAM;IACN,MAAM;IACN,OAAO;;;EAEV;AAED,wBAAgB,OAAO;IAEZ,QAAQ;IAAkB,UAAU;IAAoB,IAAI;EACtE;AAED,wBAAgB,QAAQ,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,sCAG9D;AAED,wBAAgB,SAAS,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAA;CAAE,sCAG/D"}
|
package/dist/react.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
// The provider, the hooks and <SignedIn>/<SignedOut>, over the client (src/core.ts).
|
|
3
|
+
import { createContext, useContext, useEffect, useMemo, useState } from "react";
|
|
4
|
+
import { createAccountsClient } from "./core.js";
|
|
5
|
+
const Ctx = createContext(null);
|
|
6
|
+
export function makeProvider(platform) {
|
|
7
|
+
return function AccountsProvider({ children, publishableKey, clientId, scheme, audience, ephemeral = false }) {
|
|
8
|
+
const client = useMemo(() => createAccountsClient({ publishableKey, clientId, audience, redirectUri: platform.redirectUriFor(scheme), storage: platform.storage, browser: platform.browser(ephemeral), crypto: platform.crypto }), [publishableKey, clientId, scheme, audience, ephemeral]);
|
|
9
|
+
const [state, setState] = useState(client.state);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
const off = client.subscribe(setState);
|
|
12
|
+
void client.load();
|
|
13
|
+
return off;
|
|
14
|
+
}, [client]);
|
|
15
|
+
return _jsx(Ctx.Provider, { value: { client, state }, children: children });
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function useAccounts() {
|
|
19
|
+
const c = useContext(Ctx);
|
|
20
|
+
if (!c)
|
|
21
|
+
throw new Error("Wrap your app in <AccountsProvider> (app/_layout.tsx) to use Accounts' hooks.");
|
|
22
|
+
return c;
|
|
23
|
+
}
|
|
24
|
+
export function useAuth() {
|
|
25
|
+
const { client, state } = useAccounts();
|
|
26
|
+
return {
|
|
27
|
+
isLoaded: state.isLoaded,
|
|
28
|
+
isSignedIn: state.isSignedIn,
|
|
29
|
+
userId: state.user?.id ?? null,
|
|
30
|
+
sessionId: state.sessionId,
|
|
31
|
+
getToken: client.getToken,
|
|
32
|
+
signIn: client.signIn,
|
|
33
|
+
signUp: client.signUp,
|
|
34
|
+
signOut: client.signOut,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function useUser() {
|
|
38
|
+
const { state } = useAccounts();
|
|
39
|
+
return { isLoaded: state.isLoaded, isSignedIn: state.isSignedIn, user: state.user };
|
|
40
|
+
}
|
|
41
|
+
export function SignedIn({ children }) {
|
|
42
|
+
const { state } = useAccounts();
|
|
43
|
+
return state.isLoaded && state.isSignedIn ? _jsx(_Fragment, { children: children }) : null;
|
|
44
|
+
}
|
|
45
|
+
export function SignedOut({ children }) {
|
|
46
|
+
const { state } = useAccounts();
|
|
47
|
+
return state.isLoaded && !state.isSignedIn ? _jsx(_Fragment, { children: children }) : null;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=react.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.tsx"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@iaurelius/accounts-expo",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Accounts by iAurelius for Expo: sign-in on the hosted page in an authentication session, tokens in SecureStore, useAuth() and getToken() that refreshes itself.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"auth",
|
|
7
|
+
"authentication",
|
|
8
|
+
"expo",
|
|
9
|
+
"react-native",
|
|
10
|
+
"oidc",
|
|
11
|
+
"passkeys"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://accounts.iaurelius.com",
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"sideEffects": false,
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"default": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./core": {
|
|
23
|
+
"types": "./dist/core.d.ts",
|
|
24
|
+
"default": "./dist/core.js"
|
|
25
|
+
},
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"README.md",
|
|
31
|
+
"LICENSE"
|
|
32
|
+
],
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|
|
35
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@iaurelius/accounts": "^0.1.0"
|
|
39
|
+
},
|
|
40
|
+
"peerDependencies": {
|
|
41
|
+
"expo-crypto": "*",
|
|
42
|
+
"expo-secure-store": "*",
|
|
43
|
+
"expo-web-browser": "*",
|
|
44
|
+
"react": ">=18.0.0"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/react": "19.3.0",
|
|
48
|
+
"react": "19.3.0"
|
|
49
|
+
},
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public"
|
|
52
|
+
}
|
|
53
|
+
}
|