Skip to content

Commit bb35624

Browse files
committed
docs(README): enhance SaaS token flow documentation
1 parent 114188a commit bb35624

File tree

1 file changed

+120
-5
lines changed

1 file changed

+120
-5
lines changed

README.md

Lines changed: 120 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,12 @@ npm install @genymotion/device-web-player
6868
Package import (commonJS):
6969

7070
```js
71-
const {DeviceRendererFactory} = require('genymotion/device-web-player');
71+
const {DeviceRendererFactory} = require('@genymotion/device-web-player');
7272
```
7373

7474
```html
7575
<style lang="scss">
76-
@import 'genymotion-device-web-renderer/dist/css/device-renderer.min.css';
76+
@import '@genymotion/device-web-player/dist/css/device-renderer.min.css';
7777
</style>
7878
```
7979

@@ -125,14 +125,129 @@ See the example below or explore our [detailed example](https://github.com/Genym
125125
126126
// Disconnect the device renderer, closing any open data channels.
127127
window.addEventListener('beforeunload', function () {
128-
playerAPI.disconnect();
128+
rendererAPI.VM_communication.disconnect();
129129
});
130130
</script>
131131
```
132132

133133
### 🔑 A word about the token
134134

135-
To connect a [SaaS](https://docs.genymotion.com/saas/) instance you need to generate and use a specific token. This must be done by using our [endpoint API](https://developer.genymotion.com/saas/#tag/Instances-v1/operation/accessToken). When using this API, don't forget to include the x-api-token HTTP header with a valid [Bearer](https://developer.genymotion.com/saas/#tag/Users-v1/operation/login) or [API Token](https://www.genymotion.com/blog/api-tokens-for-genymotion-saas/)
135+
For SaaS, the player requires an instance-scoped access token (`access_token`) — not a user JWT. Use exactly one authentication scheme per SaaS API request:
136+
137+
- `Authorization: Bearer <JWT>` after logging in via `POST /v1/users/login`, or
138+
- `x-api-token: <API_TOKEN>` using an API token from the SaaS portal.
139+
140+
Do not send both headers at once.
141+
142+
Flow to render a SaaS device:
143+
144+
1. Authenticate with one scheme:
145+
- JWT: `POST /v1/users/login` → response contains `token` (your JWT).
146+
- API token: skip login and use `x-api-token` directly.
147+
2. Get your instance info (for `webrtcAddress`): `GET /v1/instances/<INSTANCE_UUID>` using your chosen header.
148+
3. Generate the per-instance access token: `POST /v1/instances/access-token` with body `{"instance_uuid":"<INSTANCE_UUID>"}` using the same header.
149+
4. Use the returned `access_token` as `options.token` when calling `setupRenderer`.
150+
151+
Notes:
152+
- SaaS JWTs expire (e.g., ~48h). Regenerate by re-login when needed.
153+
- The `access_token` is scoped to a single instance and may expire; if you receive a token invalid/expired error, call the access-token endpoint again and reconnect.
154+
- For PaaS, `options.token` is the instance ID provided by your device provider. No SaaS API calls are required.
155+
156+
Useful references:
157+
- Login (JWT): https://developer.genymotion.com/saas/#operation/login
158+
- Get instance: https://developer.genymotion.com/saas/#operation/getInstance
159+
- Access token: https://developer.genymotion.com/saas/#tag/Instances-v1/operation/accessToken
160+
- API tokens overview: https://www.genymotion.com/blog/api-tokens-for-genymotion-saas/
161+
162+
### SaaS Token Flow Examples
163+
164+
Here are some practical examples for retrieving an `access_token`.
165+
166+
#### Using `curl`
167+
168+
This is useful for backend scripts or testing.
169+
170+
```bash
171+
# 1. (Optional) Login to get a JWT if you are not using an API Token
172+
JWT=$(curl -X POST https://api.geny.io/cloud/v1/users/login \
173+
-H 'Content-Type: application/json' \
174+
-d '{"email":"you@example.com","password":"<your_password>"}' | jq -r .token)
175+
176+
# 2. Get instance details (like webrtcAddress)
177+
# Using a JWT
178+
curl https://api.geny.io/cloud/v1/instances/<INSTANCE_UUID> \
179+
-H "Authorization: Bearer $JWT"
180+
181+
# Or using an API Token
182+
curl https://api.geny.io/cloud/v1/instances/<INSTANCE_UUID> \
183+
-H "x-api-token: <YOUR_API_TOKEN>"
184+
185+
# 3. Generate the access_token for the player
186+
# Using a JWT
187+
ACCESS_TOKEN=$(curl -X POST https://api.geny.io/cloud/v1/instances/access-token \
188+
-H 'Content-Type: application/json' \
189+
-H "Authorization: Bearer $JWT" \
190+
-d '{"instance_uuid":"<INSTANCE_UUID>"}' | jq -r .access_token)
191+
192+
# Or using an API Token
193+
ACCESS_TOKEN=$(curl -X POST https://api.geny.io/cloud/v1/instances/access-token \
194+
-H 'Content-Type: application/json' \
195+
-H "x-api-token: <YOUR_API_TOKEN>" \
196+
-d '{"instance_uuid":"<INSTANCE_UUID>"}' | jq -r .access_token)
197+
198+
echo "Your access token is: $ACCESS_TOKEN"
199+
```
200+
201+
#### Using JavaScript `fetch`
202+
203+
This is how you would implement it in a frontend application.
204+
205+
```javascript
206+
async function getSaasAccessToken(instanceUuid, apiToken) {
207+
try {
208+
const response = await fetch('https://api.geny.io/cloud/v1/instances/access-token', {
209+
method: 'POST',
210+
headers: {
211+
'Content-Type': 'application/json',
212+
'x-api-token': apiToken, // or 'Authorization': 'Bearer <JWT>'
213+
},
214+
body: JSON.stringify({ instance_uuid: instanceUuid }),
215+
});
216+
217+
if (!response.ok) {
218+
throw new Error(`HTTP error! status: ${response.status}`);
219+
}
220+
221+
const data = await response.json();
222+
return data.access_token;
223+
} catch (error) {
224+
console.error('Failed to get SaaS access token:', error);
225+
return null;
226+
}
227+
}
228+
229+
// Usage:
230+
const instanceUuid = '<YOUR_INSTANCE_UUID>';
231+
const apiToken = '<YOUR_API_TOKEN>'; // Or use a JWT
232+
getSaasAccessToken(instanceUuid, apiToken).then(accessToken => {
233+
if (accessToken) {
234+
// Now use this accessToken in the player options
235+
const options = {
236+
token: accessToken,
237+
// ... other options
238+
};
239+
// ... setupRenderer ...
240+
}
241+
});
242+
```
243+
244+
### Token Troubleshooting
245+
246+
If the player fails to connect, check for these common WebSocket close codes:
247+
- **4242**: The token is invalid or incorrect. Verify you are using the `access_token` for SaaS, not a JWT.
248+
- **4243**: The token has expired. Regenerate a new `access_token` using the `/v1/instances/access-token` endpoint and reconnect.
249+
- If you get HTTP 400/401 errors from the SaaS API, ensure you are using exactly one authentication header (`Authorization` or `x-api-token`), not both.
250+
136251

137252
## 🎨 Style and CSS
138253

@@ -320,7 +435,7 @@ A device renderer instance can be configured using the `options` argument (objec
320435
- **Default:** `undefined`
321436
- **Compatibility:** `PaaS`, `SaaS`
322437
- **Details:**
323-
Instance access token, the shared secret used to connect to the device. For Genymotion PaaS devices, the token is the instance id (more information can be find [here](https://docs.genymotion.com/paas/02_Getting_Started/)). For SaaS devices, you must generate the access token using the [login api](https://developer.genymotion.com/saas/#operation/login).
438+
Instance access token, the shared secret used to connect to the device. For Genymotion PaaS devices, the token is the instance id (more information can be find [here](https://docs.genymotion.com/paas/02_Getting_Started/)). For SaaS devices, you must generate the access token using the [`/v1/instances/access-token` endpoint](https://developer.genymotion.com/saas/#tag/Instances-v1/operation/accessToken).
324439

325440
#### `toolbarOrder`
326441

0 commit comments

Comments
 (0)