@authrobo/react 0.2.1 → 0.5.1

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/README.md CHANGED
@@ -1,13 +1,39 @@
1
- # @authrobo/react
2
-
3
- Drop-in React sign-in for [AuthRobo](https://authrobo.com): a configurable social
4
- button and an auth modal/panel that renders exactly the sign-in methods you've
5
- enabled in your AuthRobo dashboard (Google, LinkedIn, GitHub, Apple, email).
1
+ <p align="center">
2
+ <a href="https://authrobo.com"><img src="https://cdn.jsdelivr.net/npm/@authrobo/react/assets/hero.png" alt="AuthRobo — drop-in React sign-in" width="100%"></a>
3
+ </p>
4
+
5
+ <h1 align="center">@authrobo/react</h1>
6
+
7
+ <p align="center">
8
+ <a href="https://www.npmjs.com/package/@authrobo/react"><img src="https://img.shields.io/npm/v/@authrobo/react?logo=npm&color=4f46e5&labelColor=0b1526" alt="npm version"></a>
9
+ <a href="https://www.npmjs.com/package/@authrobo/react"><img src="https://img.shields.io/npm/dm/@authrobo/react?color=4f46e5&labelColor=0b1526" alt="npm downloads"></a>
10
+ <img src="https://img.shields.io/bundlejs/size/@authrobo/react?label=min%2Bgzip&color=4f46e5&labelColor=0b1526" alt="min+gzip size">
11
+ <img src="https://img.shields.io/badge/types-included-4f46e5?labelColor=0b1526&logo=typescript&logoColor=white" alt="TypeScript types included">
12
+ <img src="https://img.shields.io/npm/l/@authrobo/react?color=4f46e5&labelColor=0b1526" alt="MIT license">
13
+ </p>
14
+
15
+ <p align="center">
16
+ <b>Drop-in React sign-in for <a href="https://authrobo.com">AuthRobo</a>.</b><br>
17
+ Renders exactly the methods you've enabled in your dashboard — social (Google, LinkedIn,
18
+ GitHub, Apple, Facebook) plus an email switcher (<b>Magic Link · Register · Login</b>) —
19
+ or compose your own UI from a single configurable button.
20
+ </p>
6
21
 
7
22
  ```bash
8
23
  npm i @authrobo/react
9
24
  ```
10
25
 
26
+ ## Contents
27
+
28
+ - [Quick start](#quick-start) — the whole box: `<AuthRoboAuth>`
29
+ - [Just one button](#just-one-button) — `<AuthRoboButton>`, single or mapped
30
+ - [Two ways to sign in](#two-ways-to-sign-in-direct-vs-proxied) — direct vs. `startPath`
31
+ - [The proxy server contract](#the-proxy-server-contract) — routes your app implements
32
+ - [Theming](#theming)
33
+ - [API](#api)
34
+
35
+ ---
36
+
11
37
  ## Quick start
12
38
 
13
39
  Wrap your app once with your AuthRobo config:
@@ -18,7 +44,7 @@ import { AuthRoboProvider } from "@authrobo/react";
18
44
  <AuthRoboProvider
19
45
  config={{
20
46
  issuerUrl: "https://authrobo.com",
21
- clientId: process.env.NEXT_PUBLIC_AUTHROBO_CLIENT_ID!, // arc_...
47
+ clientId: process.env.NEXT_PUBLIC_AUTHROBO_CLIENT_ID!, // arc_... (public)
22
48
  redirectUri: "https://yourapp.com/auth/callback",
23
49
  }}
24
50
  >
@@ -26,18 +52,8 @@ import { AuthRoboProvider } from "@authrobo/react";
26
52
  </AuthRoboProvider>;
27
53
  ```
28
54
 
29
- ### A single provider button
30
-
31
- ```tsx
32
- import { AuthRoboButton } from "@authrobo/react";
33
-
34
- <AuthRoboButton provider="linkedin" />;
35
- ```
36
-
37
- ### The auto-configured auth panel / modal
38
-
39
- `<AuthRoboAuth>` calls AuthRobo's public `/api/v1/config` endpoint and renders a
40
- button for every method you've turned on — no need to hard-code the list.
55
+ Then drop in the full widget. It calls AuthRobo's public `/api/v1/config` and
56
+ renders only what you've enabled:
41
57
 
42
58
  ```tsx
43
59
  import { AuthRoboAuth } from "@authrobo/react";
@@ -51,26 +67,151 @@ const [open, setOpen] = useState(false);
51
67
  <AuthRoboAuth mode="modal" open={open} onClose={() => setOpen(false)} />
52
68
  ```
53
69
 
54
- ## How the flow works
70
+ **What the email switcher collects** (each tab shows exactly its flow's fields):
71
+
72
+ | Tab | Fields | Result |
73
+ | --- | --- | --- |
74
+ | **Magic Link** | email | a one-time sign-in link is emailed |
75
+ | **Register** | name · email · password | creates the account |
76
+ | **Login** | email · password | signs in |
77
+
78
+ Magic Link is first; a tab only appears if its method is enabled (`magic_link`
79
+ for Magic Link, `password` for Register + Login).
80
+
81
+ ## Just one button
82
+
83
+ Don't want the whole box? Use `<AuthRoboButton>` — it takes a `provider` and
84
+ renders that provider's branded button. Perfect for a single "Continue with
85
+ Google", or map an array to lay them out however your design wants:
86
+
87
+ ```tsx
88
+ import { AuthRoboButton } from "@authrobo/react";
89
+
90
+ // one button
91
+ <AuthRoboButton provider="google" />
92
+
93
+ // your own set, your own layout
94
+ <div className="grid gap-2">
95
+ {["google", "linkedin", "github"].map((p) => (
96
+ <AuthRoboButton key={p} provider={p} />
97
+ ))}
98
+ </div>
99
+
100
+ // custom label / classes
101
+ <AuthRoboButton provider="github" label="Sign in with GitHub" className="my-btn" />
102
+ ```
55
103
 
56
- Clicking a method navigates the browser to AuthRobo's hosted flow. After the user
57
- authenticates, AuthRobo redirects back to your `redirectUri` with a one-time
58
- `code`. **Your backend** exchanges that code (with your `client_secret`, kept
59
- server-side) for tokens — e.g. via [`@authrobo/sdk`](https://www.npmjs.com/package/@authrobo/sdk)'s
60
- `exchange()`. This package never sees your secret.
104
+ `provider` is any enabled method (`"google" | "linkedin" | "github" | "apple" |
105
+ "facebook" | "password" | "magic_link"`). Clicking begins that flow via
106
+ `startSignIn` pass `startPath` here too if you proxy (see below).
107
+
108
+ ### Neutral or branded buttons
109
+
110
+ By default social buttons share one consistent, themeable chrome (`buttonStyle="neutral"`).
111
+ Switch to `buttonStyle="branded"` to give each button its provider's own colours —
112
+ LinkedIn blue, GitHub black, Google white with a Google-blue label, Facebook blue,
113
+ Apple black (monochrome glyphs flip to white for legibility):
114
+
115
+ ```tsx
116
+ <AuthRoboAuth buttonStyle="branded" />
117
+ <AuthRoboButton provider="linkedin" buttonStyle="branded" />
118
+ ```
119
+
120
+ ## Loading &amp; the config cache
121
+
122
+ `<AuthRoboProvider>` **prefetches** your app's enabled methods the moment it
123
+ mounts — i.e. on app start — and caches them per `(issuer, clientId)`. So by the
124
+ time a login modal or page opens, the methods are already resolved: no
125
+ request-on-open, no flash. (Not using the provider? Call `prefetchAppConfig(config)`
126
+ yourself on app start.) While anything is loading, a theme-aware `<Spinner>` is
127
+ shown (it inherits `currentColor`, so it matches whatever you've themed).
128
+
129
+ ## Two ways to sign in (direct vs. proxied)
130
+
131
+ The same components support two flows; pick with the `startPath` prop.
132
+
133
+ **Direct (default).** No backend beyond one callback. Social buttons redirect to
134
+ the provider; the Login/Register forms do a native cross-origin form POST to
135
+ AuthRobo's `authorize` endpoint; Magic Link posts to `magic/start`. AuthRobo
136
+ returns to your `redirectUri` with a one-time `code`; your server exchanges it
137
+ (with your `client_secret`) for tokens. Credentials go straight to AuthRobo —
138
+ never to your own server.
139
+
140
+ ```tsx
141
+ <AuthRoboAuth /> // uses config.redirectUri
142
+ ```
143
+
144
+ **Proxied (`startPath`).** Best when you keep the session in **httpOnly
145
+ cookies**. Every action is proxied through your own server so the CSRF state
146
+ cookie and the token exchange stay first-party. Password login/register become a
147
+ same-origin JSON POST that sets your cookies with **no page redirect**, so
148
+ `onSuccess` fires and you can close your modal in place:
149
+
150
+ ```tsx
151
+ <AuthRoboAuth
152
+ startPath="/api/auth"
153
+ onSuccess={() => { refreshSession(); close(); }}
154
+ />
155
+ ```
156
+
157
+ > **Note:** in direct mode the password field lives in your app's DOM (submitted
158
+ > to AuthRobo). If you require the credential entry to be isolated on AuthRobo's
159
+ > origin, use `<AuthRoboButton provider="password" />`, which redirects to the
160
+ > hosted page instead.
161
+
162
+ ## The proxy server contract
163
+
164
+ When you pass `startPath`, the components call these routes on **your** server
165
+ (shown for `startPath="/api/auth"`). Each one forwards to AuthRobo and manages
166
+ your session cookies:
167
+
168
+ | Trigger | Request | Your route should |
169
+ | --- | --- | --- |
170
+ | Social button | `GET /api/auth/{provider}/start` | set a CSRF state cookie, redirect to AuthRobo's provider start with your callback as `redirect_uri` |
171
+ | Login | `POST /api/auth/login` `{ email, password }` | password-grant to AuthRobo, set httpOnly cookies, `2xx` |
172
+ | Register | `POST /api/auth/register` `{ name?, email, password }` | create + set cookies, `2xx` |
173
+ | Magic Link | `POST /api/auth/magic` `{ email }` | call AuthRobo `magic/start`, `2xx` |
174
+ | Callback | `GET /api/auth/{method}/callback?code=…` | exchange the code (+ `client_secret`) for tokens, set cookies |
175
+
176
+ On a non-`2xx`, return `{ "error": "message" }` — the widget shows it inline.
177
+ (See AuthRobo's docs for a copy-pasteable Next.js implementation of these routes.)
178
+
179
+ ## Theming
180
+
181
+ Styling is self-contained and theme-aware (light/dark via `prefers-color-scheme`
182
+ or a `data-theme` attribute). Override any CSS variable on an ancestor to brand
183
+ it — e.g. `--authrobo-accent` / `--authrobo-accent-fg` recolour the active tab
184
+ and the primary button:
185
+
186
+ ```css
187
+ .my-auth .authrobo-stack,
188
+ .my-auth .authrobo-btn {
189
+ --authrobo-accent: #f5b81d;
190
+ --authrobo-accent-fg: #1c1400;
191
+ --authrobo-input-bg: #070f1d;
192
+ --authrobo-btn-bg: #070f1d;
193
+ --authrobo-tabs-bg: #070f1d;
194
+ }
195
+ ```
196
+
197
+ Other tokens: `--authrobo-btn-*`, `--authrobo-input-fg`, `--authrobo-title-fg`,
198
+ `--authrobo-muted`, `--authrobo-divider-*`, `--authrobo-focus`, `--authrobo-error`.
61
199
 
62
200
  ## API
63
201
 
64
- - `AuthRoboProvider({ config, children })` — supplies config via context.
65
- - `AuthRoboButton({ provider, config?, label?, className?, style?, onClick? })` —
66
- one branded button. `provider` is `"google" | "linkedin" | "github" | "apple" | "password"`.
67
- - `AuthRoboAuth({ config?, mode?, open?, onClose?, title?, methods? })` renders
68
- all enabled methods; `methods` can restrict/reorder them.
69
- - `useAppConfig(config?)` `{ data, loading, error }` the app's branding +
70
- enabled methods.
71
- - `startSignIn(config, method, opts?)` — imperatively begin a flow.
202
+ - `AuthRoboProvider({ config, children })` — supplies config via context **and
203
+ prefetches** the app config on mount.
204
+ - `AuthRoboButton({ provider, config?, label?, className?, style?, onClick?, startPath?, lastUsed?, buttonStyle? })`
205
+ one button. `provider` is any enabled `Method`; `buttonStyle` is `"neutral" | "branded"`.
206
+ - `AuthRoboAuth({ config?, mode?, open?, onClose?, onSuccess?, title?, showHeader?, methods?, startPath?, buttonStyle? })` —
207
+ the full widget: social buttons + the email switcher. `methods` restricts/reorders;
208
+ `showHeader={false}` hides the logo/title row when you supply your own heading.
209
+ - `useAppConfig(config?)` → `{ data, loading, error }` — branding + enabled methods (cached).
210
+ - `prefetchAppConfig(config)` → `Promise<void>` — warm the cache on app start.
211
+ - `useLastMethod(clientId)` → `Method | null` — the method last used on this client.
212
+ - `startSignIn(config, method, opts?)` — imperatively begin a flow. `opts`:
213
+ `{ state?, loginHint?, screen?: "login" | "register" | "magic", startPath? }`.
214
+ - `Spinner({ style?, className? })` — the theme-aware loading spinner.
215
+ - `PROVIDER_META` / `BRAND_STYLE` — `{ label, icon }` and the branded palette per method.
72
216
 
73
217
  `config` can come from `<AuthRoboProvider>` or be passed per-component.
74
-
75
- Styling is self-contained (no CSS import needed); pass `className`/`style` to
76
- override, or restyle the `.authrobo-*` classes.
Binary file