diff --git a/docs/src/content/docs/oauth/meta.json b/docs/src/content/docs/oauth/meta.json
index 809a69c2..27996064 100644
--- a/docs/src/content/docs/oauth/meta.json
+++ b/docs/src/content/docs/oauth/meta.json
@@ -1,5 +1,5 @@
{
"title": "OAuth Providers",
- "pages": ["github", "bitbucket", "figma", "discord", "gitlab", "spotify"],
+ "pages": ["github", "bitbucket", "figma", "discord", "gitlab", "spotify", "x"],
"defaultOpen": false
}
diff --git a/docs/src/content/docs/oauth/x.mdx b/docs/src/content/docs/oauth/x.mdx
new file mode 100644
index 00000000..b18905d7
--- /dev/null
+++ b/docs/src/content/docs/oauth/x.mdx
@@ -0,0 +1,144 @@
+---
+title: X (Twitter) Authorization Provider
+description: Configure the X OAuth 2.0 provider in Aura Auth for authentication and authorization.
+---
+
+## X (Twitter)
+
+Set up the `X` authorization provider for the authentication instance in Aura Auth.
+
+---
+
+## What you'll learn
+
+Through this quick start guide, you will learn and understand the basics of how to set up the `X` provider for Aura Auth.
+
+- [X OAuth App](#x-oauth-app)
+ - [Creating an OAuth App](#creating-a-x-oauth-application)
+- [X Aura Auth](#x-aura-auth)
+ - [Installation](#installation)
+ - [Environment setup](#environment-setup)
+ - [Configure the provider](#configure-the-provider)
+ - [Get HTTP handlers](#get-http-handlers)
+- [Resources](#resources)
+
+---
+
+
+
+
+
+## X OAuth App
+
+### Creating an X OAuth Application
+
+The first step is to create and register an [`X App`](https://developer.x.com/en/portal/projects-and-apps) to grant access to the user's accessible resources like `Get my User` (used by Aura Auth), `Posts`, `Likes`, `Lists`, etc. For more detailed information, read the [X Developer Portal](https://developer.x.com/en/portal/dashboard), [Get my User](https://docs.x.com/x-api/users/get-my-user), and [OAuth 2.0 Scopes](https://docs.x.com/fundamentals/authentication/oauth-2-0/authorization-code#scopes).
+
+Creating an X OAuth app includes:
+
+- `App name`: X's app name.
+- `App permissions`: Permissions available to the X app. The options include:
+ - `Read`.
+ - `Read and write` (Recommended).
+ - `Read and write and Direct message`.
+- `Type of App`: Enables the app to work with OAuth 2.0 authentication.
+ - `Native App`: Public client with the OAuth 2.0 authorization code flow that implements PKCE. For more details, read [PKCE](https://docs.x.com/fundamentals/authentication/oauth-2-0/authorization-code). This is the option supported by Aura Auth.
+ - `Web App, Automated App or Bot`: Confidential client, which implements the `client_credentials` grant type in the authorization. For more details, read [Application only](https://docs.x.com/fundamentals/authentication/oauth-2-0/application-only).
+- `Callback URI`: The URL to which X OAuth will redirect. It should end in `/auth/callback/x` for local and production environments.
+ - Local environment: `http://localhost:3000/auth/callback/x`.
+ - Production environment: Set the URL of your production application.
+- `Website URL (Required)`: The URL of the app.
+- `Organization Name (Optional)`: The application name shown when the user tries to grant access to the app.
+- `Organization URL (Optional)`: The link shown when users authorize your app.
+- `Terms of service (Required)`: The link to the terms of service shown to the user.
+- `Privacy policy (Required)`: The link to the privacy policy shown to the user.
+
+
+
+
+
+## X Aura Auth
+
+### Installation
+
+Install the package using a package manager like `npm`, `pnpm` or `yarn`.
+
+```npm
+npm install @aura-stack/auth
+```
+
+
+
+
+
+### Environment setup
+
+Now, it's time to set up the X credentials required by Aura Auth, which include the `client Id` and `client Secret`, and write them into a `.env` file.
+
+Additionally set the `secret` used by Aura Auth to sign and encrypt the user's session.
+
+```bash title=".env" lineNumbers
+# X Credentials
+AURA_AUTH_X_CLIENT_ID="x_client_id"
+AURA_AUTH_X_CLIENT_SECRET="x_client_secret"
+
+# Aura Secret
+AURA_AUTH_SECRET="32-bytes-secret"
+```
+
+
+ The `AURA_AUTH_SECRET` is recommended to be a random and high entropy key to avoid attackers deciphering the secret used by the
+ Aura Auth application.
+
+
+
+
+
+
+### Configure the provider
+
+Set the `oauth` option of the `createAuth` instance by writing the `"x"` provider name.
+
+```ts title="@/auth" lineNumbers
+import { createAuth } from "@aura-stack/auth"
+
+export const auth = createAuth({
+ oauth: ["x"],
+})
+
+export const { handlers } = auth
+```
+
+
+
+
+
+### Get HTTP Handlers
+
+Use the HTTP handlers to consume the authentication logic and flow from the Aura Auth library to integrate it into routers and frameworks.
+
+```ts title="backend.ts" lineNumbers
+import { handlers } from "@/auth"
+
+export const { GET, POST } = handlers
+```
+
+
+ The returned handlers include pre-built routes used in OAuth flows (`/signIn/:oauth`, `/callback/:oauth`, `/session`, `/signOut`
+ and `/csrfToken`). You can mount them in Express, Hono, Next.js, or any runtime that supports native Request and Response APIs.
+
+
+
+
+
+
+---
+
+## Resources
+
+- [RFC - The OAuth 2.0 Authorization Framework](https://datatracker.ietf.org/doc/html/rfc6749)
+- [X - Developer Portal](https://developer.x.com/en/portal/projects-and-apps)
+- [X - Get my User](https://docs.x.com/x-api/users/get-my-user)
+- [X - OAuth 2.0 Authorization Code Flow with PKCE](https://docs.x.com/fundamentals/authentication/oauth-2-0/authorization-code)
+- [X - OAuth 2.0 Scopes](https://docs.x.com/fundamentals/authentication/oauth-2-0/authorization-code#scopes)
+- [X - OAuth 2.0 Bearer Token](https://docs.x.com/fundamentals/authentication/oauth-2-0/application-only)
diff --git a/packages/core/src/actions/callback/access-token.ts b/packages/core/src/actions/callback/access-token.ts
index dd5f80a5..03abef17 100644
--- a/packages/core/src/actions/callback/access-token.ts
+++ b/packages/core/src/actions/callback/access-token.ts
@@ -25,10 +25,11 @@ export const createAccessToken = async (
}
const { accessToken, clientId, clientSecret, code: codeParsed, redirectURI: redirectParsed } = parsed.data
try {
- const response = await fetch(accessToken, {
+ const request = new Request(accessToken, {
method: "POST",
headers: {
Accept: "application/json",
+
"Content-Type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
@@ -40,6 +41,7 @@ export const createAccessToken = async (
code_verifier: codeVerifier,
}).toString(),
})
+ const response = await fetch(request)
const json = await response.json()
const token = OAuthAccessTokenResponse.safeParse(json)
if (!token.success) {
diff --git a/packages/core/src/oauth/index.ts b/packages/core/src/oauth/index.ts
index e9e6e3e7..ffc7bcd5 100644
--- a/packages/core/src/oauth/index.ts
+++ b/packages/core/src/oauth/index.ts
@@ -10,6 +10,7 @@ import { figma } from "./figma.js"
import { discord } from "./discord.js"
import { gitlab } from "./gitlab.js"
import { spotify } from "./spotify.js"
+import { x } from "./x.js"
export { github } from "./github.js"
export { bitbucket } from "./bitbucket.js"
@@ -17,6 +18,7 @@ export { figma } from "./figma.js"
export { discord } from "./discord.js"
export { gitlab } from "./gitlab.js"
export { spotify } from "./spotify.js"
+export { x } from "./x.js"
export const integrations = {
github,
@@ -25,6 +27,7 @@ export const integrations = {
discord,
gitlab,
spotify,
+ x,
}
const defineOAuthEnvironment = (oauth: string) => {
diff --git a/packages/core/src/oauth/x.ts b/packages/core/src/oauth/x.ts
new file mode 100644
index 00000000..d701ca4d
--- /dev/null
+++ b/packages/core/src/oauth/x.ts
@@ -0,0 +1,38 @@
+import type { OAuthConfig } from "@/@types/index.js"
+
+/**
+ * @see [X - Get my User](https://docs.x.com/x-api/users/get-my-user)
+ */
+export interface XProfile {
+ data: {
+ id: string
+ name: string
+ username: string
+ profile_image_url: string
+ }
+}
+
+/**
+ * @see [X - Developer Portal](https://developer.x.com/en/portal/projects-and-apps)
+ * @see [X - Get my User](https://docs.x.com/x-api/users/get-my-user)
+ * @see [X - OAuth 2.0 Authorization Code Flow with PKCE](https://docs.x.com/fundamentals/authentication/oauth-2-0/authorization-code)
+ * @see [X - OAuth 2.0 Scopes](https://docs.x.com/fundamentals/authentication/oauth-2-0/authorization-code#scopes)
+ * @see [X - OAuth 2.0 Bearer Token](https://docs.x.com/fundamentals/authentication/oauth-2-0/application-only)
+ */
+export const x: OAuthConfig = {
+ id: "x",
+ name: "X",
+ authorizeURL: "https://x.com/i/oauth2/authorize",
+ accessToken: "https://api.x.com/2/oauth2/token",
+ userInfo: "https://api.x.com/2/users/me?user.fields=profile_image_url",
+ scope: "users.read users.email tweet.read offline.access",
+ responseType: "code",
+ profile({ data }) {
+ return {
+ sub: data.id,
+ name: data.name,
+ image: data.profile_image_url,
+ email: "",
+ }
+ },
+}