Authentication
Before using emusks, you must authenticate your client. emusks supports two authentication methods: auth token login and username/password login.
Auth token login
The simplest way to authenticate is with a Twitter/X auth token. This is a cookie value (auth_token) from an active browser session.
import Emusks from "emusks";
const client = new Emusks();
await client.login("your_auth_token_here");You may also provide an object if you'd like to configure proxies or a custom client:
await client.login({
auth_token: "your_auth_token_here",
// e.g. proxy: "protocol://user:pass@host:port",
});Finding your auth token
- Open x.com in your browser and log in
- Open Developer Tools (
F12orCmd+Shift+I) - Go to Application → Cookies →
https://x.com - Find the cookie named
auth_token - Copy its value
Username & password login
You can also log in with your account credentials. the default password flow uses Jetfuel and supports two-factor authentication, email verification, and alternate-identifier challenges.
const client = new Emusks();
await client.login({
type: "password",
username: "your_username",
password: "your_password",
});browser-free login with a local profile
as of 2.3.8, emusks can generate fresh Castle tokens locally from a saved signal profile. the verified browser-free path requires a compatible private profile. the profile is not included in npm, and the unprofiled DOM sandbox is not a verified replacement.
place your profile at .emusks/castle-profile.json in the working directory, set EMUSKS_CASTLE_PROFILE, or pass its path as castleProfile:
await client.login({
type: "password",
username: process.env.X_USERNAME,
password: process.env.X_PASSWORD,
castleProfile: "/private/path/castle-profile.json",
onRequest: async (type) => prompt(type),
});the profile holds previously collected browser measurements. request-specific fields and tokens are generated locally; login does not launch or contact a browser. profile-backed headers are retained for authenticated API calls. an SDK hash mismatch stops login before credential submission, so an SDK update requires a matching profile. keep this file private and ignore .emusks/ in version control. castleProfile: false disables profile loading.
2FA & email verification
If your account has two-factor authentication enabled or Twitter requests an email/phone verification, use the onRequest callback to provide the required codes:
const client = new Emusks();
await client.login({
type: "password",
username: "your_username",
password: "your_password",
onRequest: async (type) => {
if (type === "two_factor_code") {
// Return your 2FA code (e.g. from an authenticator app)
return "123456";
}
if (type === "email_code") {
// Return the code sent to your email
return "654321";
}
},
});onRequest is blocking. If Twitter asks for a code, your callback must return it before the login can continue.
handle email_code, two_factor_code, and alternate_identifier in onRequest when those values are available. the flow stops on server errors instead of resubmitting rejected credentials.
If you do rely on this, I also recommend setting all data so it can handle as much of the login flow as possible without needing to prompt you:
const client = new Emusks();
await client.login({
type: "password",
username: "your_username",
password: "your_password",
email: "your_email@example.com",
phone: "+1234567890",
onRequest: async (type) => {
if (type === "two_factor_code") return "123456";
},
});knowledge check (identity challenge)
before showing the password step, X sometimes inserts a finish_knowledge_check: it finds your account from the username or email you passed, then asks you to confirm one specific identifier tied to it. which one it wants varies by account: Username, Email, or Phone.
onRequest receives that detail as an optional second argument, so you can answer the right one instead of guessing:
await client.login({
type: "password",
username: "your_username",
password: "your_password",
onRequest: async (type, context) => {
if (type === "alternate_identifier") {
if (context?.challengeType === "Username") return "your_handle";
if (context?.challengeType === "Phone") return "+1234567890";
if (context?.challengeType === "Email") return "your_email@example.com";
}
if (type === "email_code") return "654321";
},
});context is { challengeType, accountFound, accountFoundType }, where accountFound is the value X matched and accountFoundType is "email" or "username". the second argument is optional: existing (type) => ... callbacks keep working unchanged.
if you return nothing for alternate_identifier, emusks takes X's "use password" bypass and continues to the password step, skipping the check. that works for low-risk accounts; a flagged account may re-issue the check instead.
Reference
| Option | Type | Description |
|---|---|---|
auth_token | string | Your Twitter/X auth token (use directly as the argument to login()) |
type | string | Set to "password" for username/password login |
username | string | Your Twitter/X username |
password | string | Your account password |
email | string | Email for alternate identifier challenges |
phone | string | Phone number for alternate identifier challenges |
onRequest | function | Async callback (type, context?) for interactive login challenges. type is two_factor_code, email_code, or alternate_identifier; context (on alternate_identifier) is { challengeType, accountFound, accountFoundType }. |
Elevated Access
Some sensitive actions, like reading settings, require elevated access. After logging in, call elevate() with your password:
await client.login("your_auth_token");
// Elevate your session for sensitive operations
await client.elevate("your_password");
// Now you can perform privileged actionsTIP
You only need to elevate once per session. The elevated state persists until the session ends.
Checking your session
After logging in, you can verify your session by fetching your own profile:
const me = await client.account.viewer();
console.log(`Logged in as @${me.username}`);
console.log(`Followers: ${me.stats.followers.count}`);or by checking the output of the client.login() method, which returns your user object on successful authentication.
Next steps
Head over to Configuration to learn how to choose which client to emulate, set up proxies, and customize your setup.