@@ -17,6 +17,7 @@ Demo implementations are available in the [`examples/`](./examples/) directory f
1717
1818- 🗄️ ** D1 Database Integration** : Leverage Cloudflare D1 as your primary database via Drizzle ORM.
1919- 🔌 ** KV Storage Integration** : Optionally use Cloudflare KV for secondary storage (e.g., session caching).
20+ - 📁 ** R2 File Storage** : Upload, download, and manage user files with Cloudflare R2 object storage and database tracking.
2021- 📍 ** Automatic Geolocation Tracking** : Enrich user sessions with location data derived from Cloudflare.
2122- 🌐 ** Cloudflare IP Detection** : Utilize Cloudflare's IP detection headers out-of-the-box.
2223- 🔍 ** Rich Client-Side Context** : Access timezone, city, country, region, and more via the client plugin.
@@ -27,7 +28,7 @@ Demo implementations are available in the [`examples/`](./examples/) directory f
2728- [x] Geolocation
2829- [x] D1
2930- [x] KV
30- - [ ] R2
31+ - [x ] R2
3132- [ ] Cloudflare Images
3233- [ ] Durable Objects
3334
@@ -52,6 +53,7 @@ Demo implementations are available in the [`examples/`](./examples/) directory f
5253 - [ 7. Initialize the Client] ( #7-initialize-the-client )
5354- [ Usage Examples] ( #usage-examples )
5455 - [ Accessing Geolocation Data] ( #accessing-geolocation-data )
56+ - [ R2 File Storage Guide] ( ./docs/r2.md )
5557- [ License] ( #license )
5658- [ Contributing] ( #contributing )
5759
@@ -69,11 +71,12 @@ bun add better-auth-cloudflare
6971
7072## Configuration Options
7173
72- | Option | Type | Default | Description |
73- | --------------------- | ------- | ------- | ---------------------------------------------- |
74- | ` autoDetectIpAddress ` | boolean | ` true ` | Auto-detect IP address from Cloudflare headers |
75- | ` geolocationTracking ` | boolean | ` true ` | Track geolocation data in the session table |
76- | ` cf ` | object | ` {} ` | Cloudflare geolocation context |
74+ | Option | Type | Default | Description |
75+ | --------------------- | ------- | ----------- | ---------------------------------------------- |
76+ | ` autoDetectIpAddress ` | boolean | ` true ` | Auto-detect IP address from Cloudflare headers |
77+ | ` geolocationTracking ` | boolean | ` true ` | Track geolocation data in the session table |
78+ | ` cf ` | object | ` {} ` | Cloudflare geolocation context |
79+ | ` r2 ` | object | ` undefined ` | R2 bucket configuration for file storage |
7780
7881## Setup
7982
@@ -158,6 +161,17 @@ function createAuth(env?: CloudflareBindings, cf?: IncomingRequestCfProperties)
158161 }
159162 : undefined ,
160163 kv: env ?.KV ,
164+ // Optional: Enable R2 file storage
165+ r2: {
166+ bucket: env .R2_BUCKET ,
167+ maxFileSize: 10 * 1024 * 1024 , // 10MB
168+ allowedTypes: [" .jpg" , " .jpeg" , " .png" , " .gif" , " .pdf" , " .doc" , " .docx" ],
169+ additionalFields: {
170+ category: { type: " string" , required: false },
171+ isPublic: { type: " boolean" , required: false },
172+ description: { type: " string" , required: false },
173+ },
174+ },
161175 },
162176 {
163177 emailAndPassword: {
@@ -261,8 +275,7 @@ import { createAuthClient } from "better-auth/client";
261275import { cloudflareClient } from " better-auth-cloudflare/client" ;
262276
263277const authClient = createAuthClient ({
264- // baseURL: "/api/auth", // Optional: Uncomment and adjust if your auth API routes are not at /api/auth
265- plugins: [cloudflareClient ()], // Add the Cloudflare client plugin for geolocation features
278+ plugins: [cloudflareClient ()], // includes geolocation and R2 file features (if configured)
266279});
267280
268281export default authClient ;
@@ -305,6 +318,58 @@ const displayLocationInfo = async () => {
305318displayLocationInfo ();
306319```
307320
321+ ### R2 File Storage
322+
323+ If you've configured R2 in your server setup, you can upload and manage files:
324+
325+ ``` typescript
326+ import authClient from " @/lib/authClient" ;
327+
328+ // Upload a file with metadata
329+ const uploadFile = async (file : File ) => {
330+ const result = await authClient .uploadFile (file , {
331+ category: " documents" ,
332+ isPublic: false ,
333+ description: " Important document" ,
334+ });
335+
336+ if (result .error ) {
337+ console .error (" Upload failed:" , result .error .message || " Failed to upload file. Please try again." );
338+ } else {
339+ console .log (" File uploaded:" , result .data );
340+ }
341+ };
342+
343+ // List user's files
344+ const listFiles = async () => {
345+ const result = await authClient .files .list ();
346+ if (result .data ) {
347+ console .log (" User files:" , result .data );
348+ }
349+ };
350+
351+ // Download a file
352+ const downloadFile = async (fileId : string , filename : string ) => {
353+ const result = await authClient .files .download ({ fileId });
354+ if (result .error ) {
355+ console .error (" Download failed:" , result .error );
356+ return ;
357+ }
358+
359+ // Extract blob and create download
360+ const response = result .data ;
361+ const blob = response instanceof Response ? await response .blob () : response ;
362+ const url = window .URL .createObjectURL (blob );
363+ const a = document .createElement (" a" );
364+ a .href = url ;
365+ a .download = filename ;
366+ a .click ();
367+ window .URL .revokeObjectURL (url );
368+ };
369+ ```
370+
371+ For complete R2 file storage documentation, see the [ R2 File Storage Guide] ( ./docs/r2.md ) .
372+
308373## License
309374
310375[ MIT] ( ./LICENSE )
0 commit comments