simplerauth-x-provider
v0.0.8
Published
[](https://uithub.com/janwilmake/x-oauth-client-provider/tree/main/README.md) [](https://lmpify.com?q
Readme
X OAuth Provider
This X OAuth client-provider uses the client's domain name as the client_id and automatically derives the redirect_uri from it (e.g., https://example.com/callback), eliminating the need for client registration while maintaining security through domain validation.
Setup
- Installation:
npm i simplerauth-x-providerSet environment variables:
X_CLIENT_ID: Your X OAuth app client IDX_CLIENT_SECRET: Your X OAuth app client secret
Add to your worker:
Direct flow
import {
handleOAuth,
getAccessToken,
CodeDO,
} from "simplerauth-x-provider";
export { CodeDO };
export default {
async fetch(request: Request, env: Env): Promise<Response> {
// Handle OAuth routes
const oauthResponse = await handleOAuth(request, env);
if (oauthResponse) return oauthResponse;
// Check if user is authenticated
const accessToken = getAccessToken(request);
if (!accessToken) {
// Redirect users to `/authorize?redirect_to=/dashboard` for simple login.
return Response.redirect(
"/authorize?redirect_to=" + encodeURIComponent(request.url),
);
}
// Your app logic here
return new Response("Hello authenticated user!");
},
};Enforced Authentication Flow:
import { CodeDO, withSimplerAuth } from "./x-oauth-client-provider";
export { CodeDO };
export default {
fetch: withSimplerAuth(async (request, env, ctx) => {
return new Response(
`<html><body>
<h1>X OAuth Demo</h1>
<p>Welcome, ${ctx.user.name || ctx.user.username}!</p>
<img src="${ctx.user.profile_image_url}" alt="Avatar" width="50" height="50">
<p>Username: @${ctx.user.username}</p>
<a href="/logout">Logout</a><br>
<a href="/provider">Try provider flow example</a>
</body></html>`,
{ headers: { "Content-Type": "text/html" } },
);
}),
};OAuth Provider Flow
Other apps can use standard OAuth 2.0 flow with your worker as the provider. See public/provider.html for a client example.
Client Integration Steps
- Authorization Request: Redirect users to your provider's authorize endpoint:
https://your-provider.com/authorize?client_id=CLIENT_DOMAIN&redirect_uri=REDIRECT_URI&response_type=code&state=RANDOM_STATEParameters:
client_id: Your client's domain (e.g.,example.com)redirect_uri: Where to redirect after auth (must be HTTPS and on same domain as client_id)response_type: Must becodestate: Random string for CSRF protection
- Handle Authorization Callback: After user authorizes, they'll be redirected to your
redirect_uriwith:
https://your-app.com/callback?code=AUTH_CODE&state=YOUR_STATE- Exchange Code for Token: Make a POST request to exchange the authorization code:
const response = await fetch("https://your-provider.com/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "authorization_code",
code: "AUTH_CODE_FROM_CALLBACK",
client_id: "your-domain.com",
redirect_uri: "https://your-domain.com/callback",
}),
});
const { access_token } = await response.json();- Use Access Token: Use the token to make X API requests:
const userResponse = await fetch("https://api.x.com/2/users/me", {
headers: { Authorization: `Bearer ${access_token}` },
});Security Notes
- Client domains are validated -
client_idmust be a valid domain - Redirect URIs must be HTTPS and on the same domain as
client_id - Authorization codes expire after 10 minutes
- No client registration required - the domain serves as the client identifier
Routes
/authorize- OAuth authorization endpoint/token- OAuth token endpoint/callback- X OAuth callback/logout- Logout and clear session
Notes
As an attempt at making this more agent-friendly, this uses standard OAuth 2.0. However, I also used the following logic in withSimplerAuth to tell agents where to login if they're not familiar with OAuth 2.0:
{
status: isBrowser ? 302 : 401,
headers: {
Location,
"X-Login-URL": Location,
// see https://datatracker.ietf.org/doc/html/rfc9110#name-www-authenticate
"WWW-Authenticate": `Bearer realm="main", login_url="${Location}"`,
},
}An agent not using a browser could either try and login themselves at Location, or they could pass that to a User-controlled browser to retrieve the required credentials.
