mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-10 12:27:44 +00:00
Merge remote-tracking branch 'origin/main' into v1.3
This commit is contained in:
225
CONTRIBUTING.md
225
CONTRIBUTING.md
@@ -1,30 +1,219 @@
|
||||
# Contributing to Better Auth
|
||||
|
||||
Thanks for taking the time to improve Better Auth! This is a small document to get you started.
|
||||
Thank you for your interest in contributing to Better Auth. This guide will help you get started with the contribution process.
|
||||
|
||||
## Table of Contents
|
||||
- [Code of Conduct](#code-of-conduct)
|
||||
- [Security Issues](#security-issues)
|
||||
- [Project Structure](#project-structure)
|
||||
- [Development Guidelines](#development-guidelines)
|
||||
- [Getting Started](#getting-started)
|
||||
- [Code Formatting with BiomeJS](#code-formatting-with-biomejs)
|
||||
- [Development Workflow](#development-workflow)
|
||||
- [Testing](#testing)
|
||||
- [Pull Request Process](#pull-request-process)
|
||||
- [Code Style](#code-style)
|
||||
- [Component-Specific Guidelines](#component-specific-guidelines)
|
||||
- [Core Library](#core-library)
|
||||
- [Documentation](#documentation)
|
||||
- [Plugins](#plugins)
|
||||
- [Examples](#examples)
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project and everyone participating in it is governed by our Code of Conduct. By participating, you are expected to uphold this code.
|
||||
|
||||
## Security Issues
|
||||
|
||||
If you see any security issue we prefer you to disclose it via an email (security@better-auth.com). All reports will be promptly addressed, and you'll be credited accordingly.
|
||||
For security-related issues, please email security@better-auth.com. Include a detailed description of the vulnerability and steps to reproduce it. All reports will be reviewed and addressed promptly. For more information, see our [security documentation](/docs/reference/security).
|
||||
|
||||
Learn more in our [security documentation](/docs/reference/security).
|
||||
## Project Structure
|
||||
|
||||
## A Few Guidelines to keep in mind
|
||||
The Better Auth monorepo is organized as follows:
|
||||
|
||||
- Rather than extensive configurations, focus instead on providing opinionated, best-practice defaults.
|
||||
- Try to make a consistent and predictable API across all supported frameworks
|
||||
- Everything should be type-safe and embrace typescript magic when necessary.
|
||||
- `/packages/better-auth` - Core authentication library
|
||||
- `/packages/cli` - Command-line interface tools
|
||||
- `/packages/expo` - Expo integration
|
||||
- `/packages/stripe` - Stripe payment integration
|
||||
- `/docs` - Documentation website
|
||||
- `/examples` - Example applications
|
||||
- `/demo` - Demo applications
|
||||
|
||||
## Development
|
||||
## Development Guidelines
|
||||
|
||||
1. Fork the repo
|
||||
2. clone your fork.
|
||||
3. install node.js (preferable latest LTS).
|
||||
4. run `cp -n ./docs/.env.example ./docs/.env` to create a `.env` file (if it doesn't exist)
|
||||
5. run `pnpm i` in your terminal to install dependencies.
|
||||
6. create a branch.
|
||||
7. build the project using `pnpm build`
|
||||
8. run `pnpm -F docs dev` (to run the docs section)
|
||||
9. create a draft pull request. link the relevant issue by referring to it in the PR's description. Eg.closes #123 will link the PR to issue/pull request #123.
|
||||
10. implement your changes.
|
||||
When contributing to Better Auth, please keep these principles in mind:
|
||||
|
||||
- Provide opinionated, best-practice defaults rather than extensive configurations
|
||||
- Maintain a consistent and predictable API across all supported frameworks
|
||||
- Ensure all code is type-safe and leverages TypeScript features effectively
|
||||
- Write clear, self-documenting code with appropriate comments
|
||||
- Follow existing code style and patterns
|
||||
- Keep changes focused and well-documented
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you start development, ensure you have the following:
|
||||
|
||||
- Node.js LTS (latest version recommended)
|
||||
- pnpm package manager
|
||||
- Git
|
||||
- (Optional) Any authentication provider accounts you plan to work with (Google, GitHub, etc.)
|
||||
- (Optional) Database server if working with database-related features
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Fork the repository to your GitHub account
|
||||
2. Clone your fork locally:
|
||||
```bash
|
||||
git clone https://github.com/your-username/better-auth.git
|
||||
cd better-auth
|
||||
```
|
||||
3. Install Node.js (LTS version recommended)
|
||||
4. Install pnpm if you haven't already:
|
||||
```bash
|
||||
npm install -g pnpm
|
||||
```
|
||||
5. Install project dependencies:
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
6. Create a `.env` file from the example:
|
||||
- On Unix-based systems:
|
||||
```bash
|
||||
cp -n ./docs/.env.example ./docs/.env
|
||||
```
|
||||
- On Windows:
|
||||
```cmd
|
||||
copy /Y .\docs\.env.example .\docs\.env
|
||||
```
|
||||
|
||||
7. Build the project:
|
||||
```bash
|
||||
pnpm build
|
||||
```
|
||||
|
||||
8. Run the documentation locally:
|
||||
```bash
|
||||
pnpm -F docs dev
|
||||
```
|
||||
|
||||
|
||||
## Code Formatting with BiomeJS
|
||||
|
||||
We use [BiomeJS](https://biomejs.dev/) for code formatting and linting. Before committing, please ensure your code is properly formatted:
|
||||
|
||||
```bash
|
||||
# Format all code
|
||||
pnpm format
|
||||
|
||||
# Check for linting issues
|
||||
pnpm lint
|
||||
|
||||
# Fix auto-fixable issues
|
||||
pnpm lint:fix
|
||||
```
|
||||
|
||||
## Development Workflow
|
||||
|
||||
1. Create a new branch for your changes:
|
||||
```bash
|
||||
git checkout -b type/description
|
||||
# Example: git checkout -b feat/oauth-provider
|
||||
```
|
||||
|
||||
Branch type prefixes:
|
||||
- `feat/` - New features
|
||||
- `fix/` - Bug fixes
|
||||
- `docs/` - Documentation changes
|
||||
- `refactor/` - Code refactoring
|
||||
- `test/` - Test-related changes
|
||||
- `chore/` - Build process or tooling changes
|
||||
|
||||
2. Make your changes following the code style guidelines
|
||||
3. Add tests for your changes
|
||||
4. Run the test suite:
|
||||
```bash
|
||||
# Run all tests
|
||||
pnpm test
|
||||
|
||||
# Run tests for a specific package
|
||||
pnpm --filter "{packagename}" test
|
||||
```
|
||||
5. Ensure all tests pass and the code is properly formatted
|
||||
6. Commit your changes with a descriptive message following the [Conventional Commits](https://www.conventionalcommits.org/) format:
|
||||
```
|
||||
type(scope): description
|
||||
|
||||
[optional body]
|
||||
|
||||
[optional footer(s)]
|
||||
```
|
||||
7. Push your branch to your fork
|
||||
8. Open a pull request against the main branch
|
||||
|
||||
## Testing
|
||||
|
||||
All contributions must include appropriate tests. Follow these guidelines:
|
||||
|
||||
- Write unit tests for new features
|
||||
- Ensure all tests pass before submitting a pull request
|
||||
- Update existing tests if your changes affect their behavior
|
||||
- Follow the existing test patterns and structure
|
||||
- Test across different environments when applicable
|
||||
|
||||
## Pull Request Process
|
||||
|
||||
1. Create a draft pull request early to facilitate discussion
|
||||
2. Reference any related issues in your PR description (e.g., 'Closes #123')
|
||||
3. Ensure all tests pass and the build is successful
|
||||
4. Update documentation as needed
|
||||
5. Keep your PR focused on a single feature or bug fix
|
||||
6. Be responsive to code review feedback
|
||||
7. Update the CHANGELOG.md if your changes are user-facing
|
||||
|
||||
## Code Style
|
||||
|
||||
- Follow the existing code style
|
||||
- Use TypeScript types and interfaces effectively
|
||||
- Keep functions small and focused
|
||||
- Use meaningful variable and function names
|
||||
- Add comments for complex logic
|
||||
- Update relevant documentation when making API changes
|
||||
- Follow the BiomeJS formatting rules
|
||||
|
||||
## Component-Specific Guidelines
|
||||
|
||||
### Core Library (`/packages/better-auth`)
|
||||
|
||||
- Keep the core library focused on essential authentication functionality
|
||||
- Add new authentication methods as plugins when possible
|
||||
- Ensure all public APIs are well-documented with JSDoc comments
|
||||
- Maintain backward compatibility or provide a clear migration path
|
||||
- Follow the existing patterns for error handling and logging
|
||||
|
||||
### Documentation (`/docs`)
|
||||
|
||||
- Keep documentation up-to-date with code changes
|
||||
- Use clear, concise language
|
||||
- Include code examples for common use cases
|
||||
- Document any breaking changes in the migration guide
|
||||
- Follow the existing documentation style and structure
|
||||
|
||||
### Plugins
|
||||
|
||||
- Keep plugins focused on a single responsibility
|
||||
- Follow the naming convention `@better-auth/plugin-name`
|
||||
- Document all configuration options and requirements
|
||||
- Include TypeScript type definitions
|
||||
- Add tests for all plugin functionality
|
||||
- Document any required setup or dependencies
|
||||
|
||||
### Examples (`/examples` and `/demo`)
|
||||
|
||||
- Keep examples simple and focused
|
||||
- Include a README with setup instructions
|
||||
- Document any prerequisites or setup steps
|
||||
- Keep dependencies up to date
|
||||
- Ensure examples follow security best practices
|
||||
|
||||
@@ -103,7 +103,7 @@ export default async function Page({
|
||||
GitHub
|
||||
</IconLink>
|
||||
<IconLink
|
||||
href="https://discord.com/better-auth"
|
||||
href="https://discord.gg/better-auth"
|
||||
icon={DiscordLogoIcon}
|
||||
className="flex-none text-gray-600 dark:text-gray-300"
|
||||
>
|
||||
|
||||
@@ -40,7 +40,7 @@ export async function BlogPage() {
|
||||
GitHub
|
||||
</IconLink>
|
||||
<IconLink
|
||||
href="https://discord.com/better-auth"
|
||||
href="https://discord.gg/better-auth"
|
||||
icon={DiscordLogoIcon}
|
||||
className="flex-none text-gray-600 dark:text-gray-300"
|
||||
>
|
||||
|
||||
@@ -69,7 +69,7 @@ export function Intro() {
|
||||
GitHub
|
||||
</IconLink>
|
||||
<IconLink
|
||||
href="https://discord.com/better-auth"
|
||||
href="https://discord.gg/better-auth"
|
||||
icon={DiscordLogoIcon}
|
||||
className="flex-none text-gray-600 dark:text-gray-300"
|
||||
>
|
||||
|
||||
@@ -97,7 +97,7 @@ const ChangelogPage = async () => {
|
||||
GitHub
|
||||
</IconLink>
|
||||
<IconLink
|
||||
href="https://discord.com/better-auth"
|
||||
href="https://discord.gg/better-auth"
|
||||
icon={DiscordLogoIcon}
|
||||
className="flex-none text-gray-600 dark:text-gray-300"
|
||||
>
|
||||
|
||||
@@ -1611,6 +1611,24 @@ C0.7,239.6,62.1,0.5,62.2,0.4c0,0,54,13.8,119.9,30.8S302.1,62,302.2,62c0.2,0,0.2,
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Autumn Billing",
|
||||
href: "/docs/plugins/autumn",
|
||||
isNew: true,
|
||||
icon: () => (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
width="1.2em"
|
||||
height="1.2em"
|
||||
>
|
||||
<path
|
||||
d="M3.292,20.708a1,1,0,0,1,0-1.411L6.12,16.469A8.041,8.041,0,0,1,8.03,7.041C13.072,2,20.9,3.1,20.9,3.1S22,10.928,16.959,15.97a8.041,8.041,0,0,1-9.428,1.91L4.7,20.708A1,1,0,0,1,3.292,20.708Z"
|
||||
fill="currentColor"
|
||||
></path>
|
||||
</svg>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Dub",
|
||||
href: "/docs/plugins/dub",
|
||||
|
||||
@@ -65,3 +65,10 @@ That's all! Now you can copy the Client ID and Client Secret of your app!
|
||||
<Callout>
|
||||
If you get "email_not_found" error, it's because you selected a Github app & did not configure this part!
|
||||
</Callout>
|
||||
|
||||
### Why don't I have a refresh token?
|
||||
|
||||
Github doesn't issue refresh tokens for OAuth apps. For regular OAuth apps,
|
||||
GitHub issues access tokens that remain valid indefinitely unless the user revokes them,
|
||||
the app revokes them, or they go unused for a year.
|
||||
There's no need for a refresh token because the access token doesn't expire on a short interval like Google or Discord.
|
||||
|
||||
@@ -107,3 +107,27 @@ This will trigger a new OAuth flow that requests the additional scopes. After co
|
||||
<Callout>
|
||||
Ensure you're using Better Auth version 1.2.7 or later to avoid "Social account already linked" errors when requesting additional scopes from the same provider.
|
||||
</Callout>
|
||||
|
||||
|
||||
### Always get refresh token
|
||||
|
||||
Google only issues a refresh token the first time a user consents to your app.
|
||||
If the user has already authorized your app, subsequent OAuth flows will only return an access token, not a refresh token.
|
||||
|
||||
To always get a refresh token, you can set the `accessType` to `offline`, and `prompt` to `select_account+consent` in the provider options.
|
||||
|
||||
```ts
|
||||
socialProviders: {
|
||||
google: {
|
||||
clientId: process.env.GOOGLE_CLIENT_ID as string,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
|
||||
accessType: "offline", // [!code highlight]
|
||||
prompt: "select_account+consent", // [!code highlight]
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
<Callout>
|
||||
**Revoking Access:** If you want to get a new refresh token for a user who has already authorized your app,
|
||||
you must have them revoke your app's access in their Google account settings, then re-authorize.
|
||||
</Callout>
|
||||
271
docs/content/docs/plugins/autumn.mdx
Normal file
271
docs/content/docs/plugins/autumn.mdx
Normal file
@@ -0,0 +1,271 @@
|
||||
---
|
||||
title: Autumn Billing
|
||||
description: Better Auth Plugin for Autumn Billing
|
||||
---
|
||||
|
||||
import { HomeIcon } from "lucide-react";
|
||||
import { Accordion, Accordions } from "fumadocs-ui/components/accordion";
|
||||
|
||||
[Autumn](https://useautumn.com) is open source infrastructure to run SaaS pricing plans. It sits between your app and Stripe, and acts as the database for your customers' subscription status, usage metering and feature permissions.
|
||||
|
||||
<Card href="https://discord.gg/STqxY92zuS" title="Get help on Autumn's Discord">
|
||||
We're online to help you with any questions you have.
|
||||
</Card>
|
||||
|
||||
## Features
|
||||
|
||||
- One function for all checkout, subscription and payment flows
|
||||
- No webhooks required: query Autumn for the data you need
|
||||
- Manages your application's free and paid plans
|
||||
- Usage tracking for usage billing and periodic limits
|
||||
- Custom plans and pricing changes through Autumn's dashboard
|
||||
|
||||
|
||||
<Steps>
|
||||
<Step>
|
||||
### Setup Autumn Account
|
||||
First, create your pricing plans in Autumn's [dashboard](https://app.useautumn.com), where you define what each plan and product gets access to and how it should be billed. In this example, we're handling the free and pro plans for an AI chatbot, which comes with a number of `messages` per month.
|
||||
</Step>
|
||||
<Step>
|
||||
### Install Autumn SDK
|
||||
|
||||
```package-install
|
||||
autumn-js
|
||||
```
|
||||
<Callout>
|
||||
If you're using a separate client and server setup, make sure to install the plugin in both parts of your project.
|
||||
</Callout>
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Add `AUTUMN_SECRET_KEY` to your environment variables
|
||||
|
||||
You can find it in Autumn's dashboard under "[Developer](https://app.useautumn.com/sandbox/onboarding)".
|
||||
|
||||
```bash title=".env"
|
||||
AUTUMN_SECRET_KEY=am_sk_xxxxxxxxxx
|
||||
```
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Add the Autumn plugin to your `auth` config
|
||||
|
||||
```ts title="auth.ts"
|
||||
import { autumn } from "autumn-js/better-auth";
|
||||
|
||||
export const auth = betterAuth({
|
||||
// ...
|
||||
plugins: [autumn()],
|
||||
});
|
||||
```
|
||||
<Callout>
|
||||
Autumn will auto-create your customers when they sign up, and assign them any
|
||||
default plans you created (eg your Free plan)
|
||||
</Callout>
|
||||
</Step>
|
||||
|
||||
<Step>
|
||||
### Add `<AutumnProvider />`
|
||||
|
||||
Client side, wrap your application with the AutumnProvider component, and pass in the `baseUrl` that you define within better-auth's `authClient`.
|
||||
|
||||
```tsx title="app/layout.tsx"
|
||||
import { AutumnProvider } from "autumn-js/react";
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html>
|
||||
<body>
|
||||
{/* or meta.env.BETTER_AUTH_URL for vite */}
|
||||
<AutumnProvider betterAuthUrl={process.env.NEXT_PUBLIC_BETTER_AUTH_URL}>
|
||||
{children}
|
||||
</AutumnProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
```
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
## Usage
|
||||
|
||||
### Handle payments
|
||||
|
||||
Call `attach` to redirect the customer to a Stripe checkout page when they want to purchase the Pro plan.
|
||||
|
||||
If their payment method is already on file, `AttachDialog` will open instead to let the customer confirm their new subscription or purchase, and handle the payment.
|
||||
|
||||
<Callout type="warn">
|
||||
{" "}
|
||||
Make sure you've pasted in your [Stripe test secret
|
||||
key](https://dashboard.stripe.com/test/apikeys) in the [Autumn
|
||||
dashboard](https://app.useautumn.com/integrations/stripe).
|
||||
</Callout>
|
||||
|
||||
```tsx
|
||||
import { useCustomer, AttachDialog } from "autumn-js/react";
|
||||
|
||||
export default function PurchaseButton() {
|
||||
const { attach } = useCustomer();
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={async () => {
|
||||
await attach({
|
||||
productId: "pro",
|
||||
dialog: AttachDialog,
|
||||
});
|
||||
}}
|
||||
>
|
||||
Upgrade to Pro
|
||||
</button>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
The AttachDialog component can be used directly from the `autumn-js/react`
|
||||
library (as shown in the example above), or downloaded as a [shadcn/ui component](https://docs.useautumn.com/quickstart/shadcn) to customize.
|
||||
|
||||
### Integrate Pricing Logic
|
||||
|
||||
Integrate your client and server pricing tiers logic with the following functions:
|
||||
|
||||
- `check` to see if the customer is `allowed` to send a message.
|
||||
- `track` a usage event in Autumn (typically done server-side)
|
||||
- `customer` to display any relevant billing data in your UI (subscriptions, feature balances)
|
||||
|
||||
Server-side, you can access Autumn's functions through the `auth` object.
|
||||
|
||||
<Tabs items={["Client", "Server"]}>
|
||||
<Tab value="Client">
|
||||
|
||||
```jsx
|
||||
import { useCustomer } from "autumn-js/react";
|
||||
|
||||
export default function SendChatMessage() {
|
||||
const { customer, allowed, refetch } = useCustomer();
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
onClick={async () => {
|
||||
if (allowed({ featureId: "messages" })) {
|
||||
//... send chatbot message server-side, then
|
||||
await refetch(); // refetch customer usage data
|
||||
alert(
|
||||
"Remaining messages: " + customer?.features.messages?.balance
|
||||
);
|
||||
} else {
|
||||
alert("You're out of messages");
|
||||
}
|
||||
}}
|
||||
>
|
||||
Send Message
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab value="Server">
|
||||
|
||||
```typescript Server
|
||||
import { auth } from "@/lib/auth";
|
||||
|
||||
// check on the backend if the customer can send a message
|
||||
const { allowed } = await auth.api.check({
|
||||
headers: await headers(), // pass the request headers
|
||||
body: {
|
||||
feature_id: "messages",
|
||||
},
|
||||
});
|
||||
|
||||
// server-side function to send the message
|
||||
|
||||
// then track the usage
|
||||
await auth.api.track({
|
||||
headers: await headers(),
|
||||
body: {
|
||||
feature_id: "messages",
|
||||
value: 2,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
### Additional Functions
|
||||
|
||||
#### openBillingPortal()
|
||||
|
||||
Opens a billing portal where the customer can update their payment method or cancel their plan.
|
||||
|
||||
```tsx
|
||||
import { useCustomer } from "autumn-js/react";
|
||||
|
||||
export default function BillingSettings() {
|
||||
const { openBillingPortal } = useCustomer();
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={async () => {
|
||||
await openBillingPortal({
|
||||
returnUrl: "/settings/billing",
|
||||
});
|
||||
}}
|
||||
>
|
||||
Manage Billing
|
||||
</button>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### cancel()
|
||||
|
||||
Cancel a product or subscription.
|
||||
|
||||
```tsx
|
||||
import { useCustomer } from "autumn-js/react";
|
||||
|
||||
export default function CancelSubscription() {
|
||||
const { cancel } = useCustomer();
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={async () => {
|
||||
await cancel({ productId: "pro" });
|
||||
}}
|
||||
>
|
||||
Cancel Subscription
|
||||
</button>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### Get invoice history
|
||||
|
||||
Pass in an `expand` param into `useCustomer` to get additional information. You can expand `invoices`, `trials_used`, `payment_method`, or `rewards`.
|
||||
|
||||
```tsx
|
||||
import { useCustomer } from "autumn-js/react";
|
||||
|
||||
export default function CustomerProfile() {
|
||||
const { customer } = useCustomer({ expand: ["invoices"] });
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h2>Customer Profile</h2>
|
||||
<p>Name: {customer?.name}</p>
|
||||
<p>Email: {customer?.email}</p>
|
||||
<p>Balance: {customer?.features.chat_messages?.balance}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
@@ -25,6 +25,7 @@ export const signUpEmail = <O extends BetterAuthOptions>() =>
|
||||
email: string;
|
||||
password: string;
|
||||
callbackURL?: string;
|
||||
rememberMe?: boolean;
|
||||
} & AdditionalUserFieldsInput<O>,
|
||||
},
|
||||
openapi: {
|
||||
@@ -52,6 +53,11 @@ export const signUpEmail = <O extends BetterAuthOptions>() =>
|
||||
description:
|
||||
"The URL to use for email verification callback",
|
||||
},
|
||||
rememberMe: {
|
||||
type: "boolean",
|
||||
description:
|
||||
"If this is false, the session will not be remembered. Default is `true`.",
|
||||
},
|
||||
},
|
||||
required: ["name", "email", "password"],
|
||||
},
|
||||
@@ -139,11 +145,19 @@ export const signUpEmail = <O extends BetterAuthOptions>() =>
|
||||
const body = ctx.body as any as User & {
|
||||
password: string;
|
||||
callbackURL?: string;
|
||||
rememberMe?: boolean;
|
||||
} & {
|
||||
[key: string]: any;
|
||||
};
|
||||
const { name, email, password, image, callbackURL, ...additionalFields } =
|
||||
body;
|
||||
const {
|
||||
name,
|
||||
email,
|
||||
password,
|
||||
image,
|
||||
callbackURL,
|
||||
rememberMe,
|
||||
...additionalFields
|
||||
} = body;
|
||||
const isValidEmail = z.string().email().safeParse(email);
|
||||
|
||||
if (!isValidEmail.success) {
|
||||
@@ -275,16 +289,21 @@ export const signUpEmail = <O extends BetterAuthOptions>() =>
|
||||
const session = await ctx.context.internalAdapter.createSession(
|
||||
createdUser.id,
|
||||
ctx,
|
||||
rememberMe === false,
|
||||
);
|
||||
if (!session) {
|
||||
throw new APIError("BAD_REQUEST", {
|
||||
message: BASE_ERROR_CODES.FAILED_TO_CREATE_SESSION,
|
||||
});
|
||||
}
|
||||
await setSessionCookie(ctx, {
|
||||
await setSessionCookie(
|
||||
ctx,
|
||||
{
|
||||
session,
|
||||
user: createdUser,
|
||||
});
|
||||
},
|
||||
rememberMe === false,
|
||||
);
|
||||
return ctx.json({
|
||||
token: session.token,
|
||||
user: {
|
||||
|
||||
@@ -18,6 +18,9 @@ export function getOAuth2Tokens(data: Record<string, any>): OAuth2Tokens {
|
||||
accessTokenExpiresAt: data.expires_in
|
||||
? getDate(data.expires_in, "sec")
|
||||
: undefined,
|
||||
refreshTokenExpiresAt: data.refresh_token_expires_in
|
||||
? getDate(data.refresh_token_expires_in, "sec")
|
||||
: undefined,
|
||||
scopes: data?.scope
|
||||
? typeof data.scope === "string"
|
||||
? data.scope.split(" ")
|
||||
|
||||
@@ -56,6 +56,11 @@ export const username = (options?: UsernameOptions) => {
|
||||
description: "Remember the user session",
|
||||
})
|
||||
.optional(),
|
||||
callbackURL: z
|
||||
.string({
|
||||
description: "The URL to redirect to after the user signs in",
|
||||
})
|
||||
.optional(),
|
||||
}),
|
||||
metadata: {
|
||||
openapi: {
|
||||
|
||||
@@ -76,12 +76,15 @@ export const facebook = (options: FacebookOptions) => {
|
||||
|
||||
/* limited login */
|
||||
// check is limited token
|
||||
if (token.split(".").length) {
|
||||
if (token.split(".").length === 3) {
|
||||
try {
|
||||
const { payload: jwtClaims } = await jwtVerify(
|
||||
token,
|
||||
createRemoteJWKSet(
|
||||
new URL("https://www.facebook.com/.well-known/oauth/openid/jwks"),
|
||||
// https://developers.facebook.com/docs/facebook-login/limited-login/token/#jwks
|
||||
new URL(
|
||||
"https://limited.facebook.com/.well-known/oauth/openid/jwks/",
|
||||
),
|
||||
),
|
||||
{
|
||||
algorithms: ["RS256"],
|
||||
@@ -122,7 +125,7 @@ export const facebook = (options: FacebookOptions) => {
|
||||
return options.getUserInfo(token);
|
||||
}
|
||||
|
||||
if (token.idToken) {
|
||||
if (token.idToken && token.idToken.split(".").length === 3) {
|
||||
const profile = decodeJwt(token.idToken) as {
|
||||
sub: string;
|
||||
email: string;
|
||||
|
||||
@@ -74,6 +74,9 @@ export const google = (options: GoogleOptions) => {
|
||||
: ["email", "profile", "openid"];
|
||||
options.scope && _scopes.push(...options.scope);
|
||||
scopes && _scopes.push(...scopes);
|
||||
if (options.prompt === "select_account+consent")
|
||||
//@ts-expect-error - Google expects there to be a space not `+` in the prompt
|
||||
options.prompt = "select_account consent";
|
||||
const url = await createAuthorizationURL({
|
||||
id: "google",
|
||||
options,
|
||||
|
||||
Reference in New Issue
Block a user