Overview
Enterprise Feature : The programmatic Link authentication methods documented on this page are part of Enterprise Whitelabel and require approval before use. Contact [email protected] to request access.
The Link module (sdk.link) provides direct authentication capabilities for building custom login experiences. This is intended for approved enterprise partners who need full control over the authentication flow.
For most applications : Use Hosted Mode or Link Embed instead. These provide excellent user experiences and are available immediately without approval.
Session Initialization
initSession(options)
Initialize a new authentication session for OnlyFans login.
options
InitSessionOptions
required
Configuration for the authentication session.
options.clientReferenceId
A unique identifier for this session. Use this to track sessions in your application.
Optional webhook URL to receive authentication status updates.
The session secret used for subsequent authentication operations.
Internal session identifier.
Initialize Session (Enterprise Only)
// Requires Enterprise Whitelabel approval
const authSession = await sdk . link . initSession ({
mode: "whitelabel" ,
clientReferenceId: "user_123_session_" + Date . now (),
webhook: "https://your-app.com/webhooks/auth" // Optional
})
console . log ( "Session secret:" , authSession . clientSecret )
// Store this secret for subsequent authentication calls
{
"data" : {
"clientSecret" : "cs_1234567890abcdef" ,
"sessionId" : "session_abcdef123456"
},
"error" : undefined
}
Login Methods
loginWithCredentials(clientSecret, email, password, proxyOptions?)
Attempt to log in to OnlyFans using email and password credentials.
The client secret obtained from initSession().
The user’s OnlyFans email address.
The user’s OnlyFans password.
Optional proxy configuration for the login request.
status
'completed' | 'awaiting_2fa' | 'failed'
required
The login attempt status.
Present when status is ‘completed’. Contains the session data for API calls. Authentication headers to use for OnlyFans API calls.
Basic user information for the authenticated account.
Present when status is ‘failed’. Contains the error message.
Login with Email/Password
const loginResult = await sdk . link . loginWithCredentials (
authSession . clientSecret ,
"[email protected] " ,
"secure_password_123" ,
{
url: "http://proxy_user:[email protected] :8080" // Optional
}
)
if ( loginResult . status === "completed" ) {
const session = loginResult . data . session
console . log ( "Login successful!" )
// Store session securely for API calls
await storeUserSession ( loginResult . data . user . id , session )
} else if ( loginResult . status === "awaiting_2fa" ) {
console . log ( "2FA required" )
// Prompt user for 2FA code
} else {
console . error ( "Login failed:" , loginResult . error )
}
{
"status" : "completed" ,
"data" : {
"session" : {
"user-id" : "123456789" ,
"x-bc" : "random_browser_context_string" ,
"cookie" : "session_cookies_here" ,
"user-agent" : "Mozilla/5.0..."
},
"user" : {
"id" : "123456789" ,
"username" : "example_user" ,
"name" : "Example User" ,
"email" : "[email protected] "
}
}
}
{
"status" : "awaiting_2fa" ,
"data" : {
"twoFactorState" : {
"options" : [ "app" , "phone" ],
"phoneLast4" : "1234" ,
"phoneCode" : {
"checkAttemptsLeft" : 2 ,
"checkAttemptsLimit" : 3 ,
"expirationDate" : "2025-02-13T07:20:11+00:00" ,
"expirationSeconds" : 300 ,
"lastSentDate" : "2025-02-13T07:15:11+00:00" ,
"requestAttemptsLeft" : 2 ,
"requestAttemptsLimit" : 3
}
}
}
}
submitTwoFactorCode(clientSecret, code)
Submit a two-factor authentication code when login requires 2FA.
The client secret from the authentication session.
The 6-digit 2FA code from the user’s authenticator app.
status
'completed' | 'failed'
required
The 2FA verification status.
Present when status is ‘completed’. Contains session and user data.
Present when status is ‘failed’. Contains the error message.
// After login returns "awaiting_2fa" status
const twoFactorCode = await getTwoFactorCodeFromUser () // Your UI implementation
const otpResult = await sdk . link . submitTwoFactorCode (
authSession . clientSecret ,
twoFactorCode
)
if ( otpResult . status === "completed" ) {
const session = otpResult . data . session
console . log ( "2FA verification successful!" )
// Store session for API calls
await storeUserSession ( otpResult . data . user . id , session )
} else {
console . error ( "2FA failed:" , otpResult . error )
// Allow user to retry or go back to password entry
}
{
"status" : "completed" ,
"data" : {
"session" : {
"user-id" : "123456789" ,
"x-bc" : "browser_context_after_2fa" ,
"cookie" : "updated_session_cookies" ,
"user-agent" : "Mozilla/5.0..."
},
"user" : {
"id" : "123456789" ,
"username" : "example_user" ,
"name" : "Example User" ,
"email" : "[email protected] "
}
}
}
Session Status
getAuthenticationStatus(clientSecret)
Check the current status of an authentication session.
The client secret from the authentication session.
status
'pending' | 'completed' | 'failed' | 'expired'
required
Current authentication status.
Present when status is ‘completed’. Contains session and user data.
Present when status is ‘failed’ or ‘expired’.
Check Authentication Status
const status = await sdk . link . getAuthenticationStatus (
authSession . clientSecret
)
switch ( status . status ) {
case "pending" :
console . log ( "Authentication still in progress..." )
break
case "completed" :
console . log ( "Authentication successful!" )
const session = status . data . session
// Use session for API calls
break
case "failed" :
console . error ( "Authentication failed:" , status . error )
break
case "expired" :
console . log ( "Session expired, need to start over" )
break
}
Complete Authentication Flow
Here’s a complete example showing the full authentication flow with error handling:
Complete Authentication Example
async function authenticateUser (
email : string ,
password : string ,
getTwoFactorCode : () => Promise < string >
) : Promise <{ session : any ; user : any } | null > {
try {
// Step 1: Initialize session
const authSession = await sdk . link . initSession ({
mode: "whitelabel" ,
clientReferenceId: `auth_ ${ Date . now () } _ ${ Math . random () } `
})
console . log ( "Session initialized:" , authSession . clientSecret )
// Step 2: Attempt login
const loginResult = await sdk . link . loginWithCredentials (
authSession . clientSecret ,
email ,
password
)
if ( loginResult . status === "completed" ) {
// Login successful without 2FA
console . log ( "Login successful!" )
return {
session: loginResult . data . session ,
user: loginResult . data . user
}
}
if ( loginResult . status === "awaiting_2fa" ) {
// Step 3: Handle 2FA if required
console . log ( "2FA required, requesting code..." )
const twoFactorCode = await getTwoFactorCode ()
const otpResult = await sdk . link . submitTwoFactorCode (
authSession . clientSecret ,
twoFactorCode
)
if ( otpResult . status === "completed" ) {
console . log ( "2FA verification successful!" )
return {
session: otpResult . data . session ,
user: otpResult . data . user
}
} else {
console . error ( "2FA verification failed:" , otpResult . error )
return null
}
}
// Login failed
console . error ( "Login failed:" , loginResult . error )
return null
} catch ( error ) {
console . error ( "Authentication error:" , error )
return null
}
}
// Usage
const authResult = await authenticateUser (
"[email protected] " ,
"password123" ,
async () => {
// Your implementation to get 2FA code from user
return prompt ( "Enter 2FA code:" )
}
)
if ( authResult ) {
console . log ( "Authenticated as:" , authResult . user . username )
// Now you can use the session for API calls
const { data : profile } = await sdk . self . getMe ({
authentication: { session: authResult . session }
})
console . log ( "Profile loaded:" , profile )
} else {
console . log ( "Authentication failed" )
}
Error Handling
Authentication methods can fail for various reasons. Here are common error scenarios:
Invalid Credentials
const loginResult = await sdk . link . loginWithCredentials (
clientSecret ,
"[email protected] " ,
"wrong_password"
)
if ( loginResult . status === "failed" ) {
console . error ( "Invalid credentials:" , loginResult . error )
// Show error message to user
}
Account Restrictions
// Some accounts may be restricted or suspended
if ( loginResult . status === "failed" &&
loginResult . error . includes ( "restricted" )) {
console . log ( "Account has restrictions" )
// Handle account restriction scenario
}
Network Issues
try {
const loginResult = await sdk . link . loginWithCredentials (
clientSecret ,
email ,
password
)
} catch ( error ) {
if ( error . message . includes ( "network" ) ||
error . message . includes ( "timeout" )) {
console . log ( "Network error, please try again" )
// Implement retry logic
}
}
Best Practices
Security : Never log or store passwords in plain text. Always use secure storage for session data and implement proper session expiration.
Session Management : Sessions can expire. Implement session validation and refresh logic in your application.
Rate Limiting : Authentication endpoints are rate limited. Don’t attempt too many login requests in quick succession.
Secure Session Storage
// Example secure session storage
import crypto from "crypto"
const ENCRYPTION_KEY = process . env . SESSION_ENCRYPTION_KEY // 32 bytes key
function encryptSession ( sessionData : any ) : string {
const iv = crypto . randomBytes ( 16 )
const cipher = crypto . createCipher ( 'aes-256-cbc' , ENCRYPTION_KEY )
let encrypted = cipher . update ( JSON . stringify ( sessionData ), 'utf8' , 'hex' )
encrypted += cipher . final ( 'hex' )
return iv . toString ( 'hex' ) + ':' + encrypted
}
function decryptSession ( encryptedData : string ) : any {
const [ ivHex , encrypted ] = encryptedData . split ( ':' )
const iv = Buffer . from ( ivHex , 'hex' )
const decipher = crypto . createDecipher ( 'aes-256-cbc' , ENCRYPTION_KEY )
let decrypted = decipher . update ( encrypted , 'hex' , 'utf8' )
decrypted += decipher . final ( 'utf8' )
return JSON . parse ( decrypted )
}
// Store session securely
async function storeSession ( userId : string , session : any ) {
const encrypted = encryptSession ( session )
await database . sessions . upsert ({
where: { userId },
update: {
sessionData: encrypted ,
updatedAt: new Date ()
},
create: {
userId ,
sessionData: encrypted ,
createdAt: new Date (),
updatedAt: new Date ()
}
})
}
Next Steps