Sessions are the foundation of Uplink’s security and connection model. Understanding how to create, manage, and secure sessions is essential for production use.
What is a session?
A session is an authenticated WebSocket connection that allows your JavaScript code to communicate with mobile devices. Sessions are identified by JWT tokens and enable secure, real-time bidirectional communication.
const client = await uplink . client . connect ( 'wss://relay.uplink.build/session/<jwt>' )
Creating sessions
Sessions are created through the Uplink Console and authenticated using JWT tokens.
Generate an API key
In your Console , navigate to Settings → API Keys and create a new API key. API keys are used to generate session tokens.
Create a session
Go to Sessions → New Session to generate a session JWT token. The token encodes the session permissions and expiration.
Connect using the token
Use the generated JWT in your WebSocket connection URL: const client = await uplink . client . connect (
'wss://relay.uplink.build/session/<your-jwt-token>'
)
Session tokens (JWT)
Session tokens are JSON Web Tokens (JWT) that contain:
Session ID : Unique identifier for the session
Permissions : What operations are allowed
Expiration : When the token expires
Scope : Which devices can connect
Token security best practices
Treat JWT tokens like passwords. Never commit them to source control or expose them in client-side code. // ✓ Good: Use environment variables
const sessionUrl = process . env . UPLINK_SESSION_URL
// ✗ Bad: Hardcoded tokens
const sessionUrl = 'wss://relay.uplink.build/session/eyJ...'
Use short expiration times
Configure session tokens with appropriate expiration times. For automated testing, consider short-lived tokens that are regenerated for each test run.
Scope permissions appropriately
Create tokens with only the permissions needed for the specific use case. Don’t use admin tokens for routine automation.
Regularly rotate API keys and session tokens, especially after team member changes or security incidents.
Session lifecycle
Connection
When you connect to a session, the client establishes a WebSocket connection to the Uplink relay server:
const client = await uplink . client . connect ( 'wss://relay.uplink.build/session/<jwt>' )
console . log ( 'Connected to session' )
// The client is now ready to interact with devices
Active session
During an active session:
Devices can connect and disconnect
Browsers can be launched and managed
Commands are sent in real-time
Events are emitted for device state changes
client . on ( 'worker-connected' , ( device ) => {
console . log ( 'Device joined session:' , device . address )
})
client . on ( 'worker-disconnected' , ( device ) => {
console . log ( 'Device left session:' , device . address )
})
Closing a session
Always close the client when you’re done to properly clean up resources:
// Clean up in order: pages, browsers, then client
await page . close ()
await browser . close ()
await client . close ()
Session expiration
Sessions expire when:
The JWT token reaches its expiration time
The connection is closed by the client
The session is terminated in the Console
The API key used to create the session is revoked
When a session expires, all connected devices are disconnected and browsers are closed. Plan for graceful handling of session expiration in long-running automations.
Authentication patterns
Development
For development, you can manually create session tokens in the Console:
// .env file
UPLINK_SESSION_URL = wss : //relay.uplink.build/session/eyJhbGc...
// In your code
import uplink from '@uplink-code/uplink'
const client = await uplink . client . connect ( process . env . UPLINK_SESSION_URL )
Production
In production, generate session tokens programmatically using the Uplink API:
// Pseudo-code: Generate session token via API
async function createSession () {
const response = await fetch ( 'https://api.uplink.build/sessions' , {
method: 'POST' ,
headers: {
'Authorization' : `Bearer ${ process . env . UPLINK_API_KEY } ` ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
expiresIn: '1h' ,
permissions: [ 'launch' , 'browse' ]
})
})
const { sessionUrl } = await response . json ()
return sessionUrl
}
const sessionUrl = await createSession ()
const client = await uplink . client . connect ( sessionUrl )
CI/CD integration
For automated testing in CI/CD pipelines:
# Example GitHub Actions workflow
- name : Run Uplink tests
env :
UPLINK_API_KEY : ${{ secrets.UPLINK_API_KEY }}
run : |
npm test
// In your test suite
beforeAll ( async () => {
const sessionUrl = await createUplinkSession ( process . env . UPLINK_API_KEY )
client = await uplink . client . connect ( sessionUrl )
})
afterAll ( async () => {
await client . close ()
})
Multi-session patterns
Isolating test runs
Create separate sessions for parallel test runs to avoid conflicts:
// Each test worker gets its own session
async function setupTestSession ( workerId : string ) {
const sessionUrl = await createSession ({
label: `test-worker- ${ workerId } ` ,
expiresIn: '1h'
})
return uplink . client . connect ( sessionUrl )
}
Load distribution
For high-volume automation, distribute load across multiple sessions:
const sessions = await Promise . all ([
createAndConnectSession ( 'session-1' ),
createAndConnectSession ( 'session-2' ),
createAndConnectSession ( 'session-3' )
])
// Round-robin device allocation
const device = sessions [ nextIndex ++ % sessions . length ]
Error handling
Handle authentication and connection errors gracefully:
try {
const client = await uplink . client . connect ( sessionUrl )
} catch ( error ) {
if ( error . message . includes ( 'unauthorized' )) {
console . error ( 'Invalid or expired session token' )
} else if ( error . message . includes ( 'connection' )) {
console . error ( 'Failed to connect to Uplink relay' )
} else {
console . error ( 'Unexpected error:' , error )
}
}
Next steps