Qué es un cliente de servicio
- Perteneciente al proyecto. El proyecto conserva el cliente cuando la persona o agente que lo creó se va. Sus solicitudes se facturan como solicitudes de agente, contra las mismas solicitudes incluidas.
- Solo lectura, Proponer o Administrar. Se establece al crear, como un agente conectado. Solo lectura lista y lee; Proponer también sube multimedia y propone cambios en listas de reproducción y pantallas para que una persona los revise; Administrar también cambia, publica y gasta. Cuando el proyecto requiere revisión para cambios de agentes, un cliente trabaja como Proponer como máximo. Vea Solo lectura, Proponer y Administrar.
- Capacidades. Cualquiera de
screens,content,playlists,advertising,reportsyproject, dentro de las propias del creador. - Limitado. Un cliente de servicio nunca crea ni administra clientes de servicio, miembros, invitaciones o inicios de sesión de agentes.
- Dos formas de iniciar sesión. Una clave pública registrada (
private_key_jwt, la forma recomendada) o un secreto (client_secret_basic). Un cliente puede tener hasta dos de cada uno, para que pueda rotar sin tiempo de inactividad.
Una organización contiene hasta 50 clientes de servicio en vivo en todos sus proyectos. Los ids de cliente comienzan con scl_ y los secretos con sr_cs_.
Crear una clave
Generar un par de claves Ed25519 en la máquina que ejecuta el cliente. La clave privada nunca sale de ella; screenRIG solo conserva la mitad pública.
openssl genpkey -algorithm ed25519 -out screenrig-client.pem
chmod 600 screenrig-client.pemTambién funcionan claves EC P-256 y claves RSA de al menos 2048 bits.
Crear el cliente
En el panel. Abra Acceso y elija Nuevo cliente de servicio. Asígnelo un nombre, elija Solo lectura, Proponer o Administrar, marque sus capacidades y pegue la clave pública como JWK, o elija Generar un secreto de cliente. Imprima el JWK público de su clave con Node:
node -e 'const c=require("node:crypto");const k=c.createPublicKey(require("node:fs").readFileSync("screenrig-client.pem"));console.log(JSON.stringify(k.export({format:"jwk"})))'Con la CLI. El agente necesita acceso Gestionar para su identidad con el ámbito identity, su propia autorización Gestionar con la capacidad project en el proyecto de destino y una persona responsable verificada que administre la organización de ese proyecto.
Para un agente recién inscrito, la persona invitada debe aceptar primero la invitación de inscripción. El acceso Gestionar al proyecto por sí solo no autoriza cambios de credenciales.
--key-file acepta un archivo JWK o PEM y envía solo su parte pública:
screenrig service-client create --name "Nightly report" --access read \
--capability reports --key-file screenrig-client.pemPara usar un secreto en su lugar, agregue --secret-file PATH. La CLI escribe el secreto en ese nuevo archivo con modo 0600; se muestra una vez y nunca más.
screenrig service-client show scl_ID lista las claves del cliente (kid) y los identificadores secretos. Una clave sin su propio kid se conoce por su huella RFC 7638.
Clientes usuarios de carga
El agente de una agencia recibe un cliente limitado a listas de reproducción y carpetas de medios elegidas: añada --uploader --folder-id mfd_FOLDER[,mfd_FOLDER] --playlist-id pl_PLAYLIST[,pl_PLAYLIST] a service-client create. Un cliente usuario de carga solo tiene las capacidades content y playlists y actúa en Proponer salvo que --access indique otra cosa. Con su token sube a sus carpetas (screenrig media upload FILE --folder mfd_FOLDER) y añade, reemplaza y elimina páginas de sus listas de reproducción (screenrig playlist page add|replace|remove); todo lo demás responde outside_upload_scope, cuyo upload_scope enumera lo que puede usar. El propietario del proyecto cambia más tarde las carpetas y listas de reproducción de un cliente; el cambio se aplica al token ya emitido. Consulte Usuarios de carga.
Obtener un token de acceso
Solicite al endpoint de token un token con el permiso client_credentials. La respuesta incluye access_token, token_type: Bearer, expires_in (900 segundos) y scope. No hay token de actualización: solicítelo de nuevo cuando expire.
Con un secreto, autentíquese con HTTP Basic. Se rechaza un secreto en el cuerpo de la solicitud:
curl -s https://api.screenrig.ai/oauth/token \
-u "$SCREENRIG_CLIENT_ID:$SCREENRIG_CLIENT_SECRET" \
-d grant_type=client_credentialsCon una clave, envíe una afirmación de cliente firmada en lugar de un secreto:
curl -s https://api.screenrig.ai/oauth/token \
-d grant_type=client_credentials \
-d client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer \
-d client_assertion="$ASSERTION"La afirmación es un JWT firmado con su clave privada:
| Campo | Valor |
|---|---|
Encabezado alg | EdDSA, ES256 o RS256, coincidiendo con la clave |
Encabezado kid | El id de la clave registrada |
iss y sub | El id del cliente. |
aud | https://api.screenrig.ai o https://api.screenrig.ai/oauth/token, como una sola cadena |
iat, exp | Máximo 5 minutos de diferencia |
jti | Un nuevo valor aleatorio para cada afirmación; se rechaza una repetición |
Los encabezados jku, x5u, jwk y x5c son rechazados.
Solicite menos
Dos parámetros opcionales limitan un token:
scope:access:readoaccess:proposeda al token un nivel inferior al del cliente, y los nombres de capacidades mantienen solo esas capacidades, por ejemploscope=access:read reports. Un alcance más allá del cliente esinvalid_scope.resource:https://api.screenrig.ai/api, el predeterminado, para la API REST, ohttps://api.screenrig.ai/mcppara el servidor remoto.
Llamar a la API
Envíe el token como portador. Actúa sobre el propio proyecto del cliente:
curl -s https://api.screenrig.ai/api/screens \
-H "Authorization: Bearer $TOKEN"Node: un token en caché con una clave
Este ayudante firma la afirmación con la criptografía incorporada de Node, mantiene el token en memoria y solicita uno nuevo un minuto antes de que expire. Configure CLIENT_KEY_ID con el kid de la clave desde service-client show:
import { createPrivateKey, randomUUID, sign } from "node:crypto";
import { readFileSync } from "node:fs";
const ISSUER = "https://api.screenrig.ai";
const { SCREENRIG_CLIENT_ID: clientId, SCREENRIG_CLIENT_KEY_FILE: keyFile, CLIENT_KEY_ID: kid } = process.env;
const key = createPrivateKey(readFileSync(keyFile));
const part = (value) => Buffer.from(JSON.stringify(value)).toString("base64url");
let cached;
function assertion() {
const now = Math.floor(Date.now() / 1000);
const input = `${part({ alg: "EdDSA", typ: "JWT", kid })}.${part({ iss: clientId, sub: clientId, aud: ISSUER, iat: now, exp: now + 60, jti: randomUUID() })}`;
return `${input}.${sign(null, Buffer.from(input), key).toString("base64url")}`;
}
export async function accessToken() {
if (cached && cached.expiresAt - 60_000 > Date.now()) return cached.token;
const response = await fetch(`${ISSUER}/oauth/token`, {
method: "POST",
body: new URLSearchParams({
grant_type: "client_credentials",
client_assertion_type: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer",
client_assertion: assertion(),
}),
});
const body = await response.json();
if (!response.ok) throw new Error(`screenRIG token request refused: ${body.error}: ${body.error_description ?? ""}`);
cached = { token: body.access_token, expiresAt: Date.now() + body.expires_in * 1000 };
return cached.token;
}Python: un token en caché con un secreto
import base64, json, os, time, urllib.parse, urllib.request
ISSUER = "https://api.screenrig.ai"
_cached = {"token": None, "expires_at": 0.0}
def access_token() -> str:
if _cached["token"] and _cached["expires_at"] - 60 > time.time():
return _cached["token"]
pair = f'{os.environ["SCREENRIG_CLIENT_ID"]}:{os.environ["SCREENRIG_CLIENT_SECRET"]}'
request = urllib.request.Request(
f"{ISSUER}/oauth/token",
data=urllib.parse.urlencode({"grant_type": "client_credentials"}).encode(),
headers={"Authorization": "Basic " + base64.b64encode(pair.encode()).decode()},
)
with urllib.request.urlopen(request, timeout=10) as response:
body = json.load(response)
_cached.update(token=body["access_token"], expires_at=time.time() + body["expires_in"])
return body["access_token"]Ejecute la CLI como cliente de servicio
Inicie sesión en la CLI como el cliente una sola vez, en una configuración propia. La configuración registra el cliente y el archivo que contiene su clave privada (recomendada) o su secreto, nunca la clave ni el secreto en sí:
screenrig --config /run/screenrig/ci.json login --client-id scl_ID \
--client-key-file /run/secrets/screenrig-client.pem
screenrig --config /run/screenrig/ci.json screen listUse --client-secret-file FILE en lugar de --client-key-file para un secreto. Cada comando que usa esa configuración se ejecuta como el cliente sin paso de inicio de sesión: lee el archivo de clave o de secreto cada vez (por eso un archivo rotado no necesita un nuevo inicio de sesión), mantiene el token en memoria y no escribe nada más en la configuración. screenrig logout elimina el cliente de ella. Cada comando solicita su propio token, por lo que un trabajo que ejecuta más de unos cientos de comandos por hora se beneficia más de un token reutilizado a través de la API.
Rotar y revocar
| Para | Panel (Acceso, el cliente) | CLI |
|---|---|---|
| Agregar una segunda clave | Agregar clave | screenrig service-client add-key scl_ID --key-file new.pem |
| Eliminar una clave | Eliminar clave | screenrig service-client remove-key scl_ID --kid KID |
| Agregar un segundo secreto | Generar secreto | screenrig service-client add-secret scl_ID --secret-file new-secret |
| Eliminar un secreto | Eliminar secreto | screenrig service-client remove-secret scl_ID --secret-id css_ID |
| Cambiar acceso o capacidades | Acceso, luego Guardar acceso | Use el dashboard |
| Finalizar el cliente | Revocar | screenrig service-client revoke scl_ID --yes |
Para rotar sin tiempo de inactividad, agregue la nueva clave o secreto, despliegue y luego elimine el antiguo. Los tokens emitidos con una clave o secreto eliminado dejan de funcionar en segundos, y un cliente mantiene al menos una clave o secreto.
Restringir el acceso o las capacidades de un cliente termina sus tokens actuales; su próximo token tendrá el nuevo acceso. Revocar es permanente: las claves y secretos se eliminan, los tokens del cliente dejan de funcionar en segundos y el registro permanece en la página de Acceso para auditoría. Eliminar el proyecto revoca sus clientes.
Un cliente obtiene tokens solo mientras su proyecto está activo. Un proyecto cancelado o eliminado no emite tokens. Un proyecto con crédito cero aún emite tokens, y sus solicitudes pagadas responden 402 payment_required, como lo hace un agente.
Errores y límites
| Respuesta | Causa | Corregir |
|---|---|---|
401 invalid_client | Secreto incorrecto o eliminado, una afirmación mala o repetida, un kid desconocido, un cliente revocado o un proyecto cancelado o eliminado | Verifique las credenciales contra service-client show; envíe un jti nuevo cada vez |
400 invalid_scope | Un alcance más allá del acceso o capacidades del cliente | Solicite menos o cambie el cliente |
400 invalid_target | Un resource distinto a los dos listados | Use el predeterminado o el servidor remoto |
429 rate_limited | Más de 600 tokens por cliente, o 1,200 solicitudes de token por dirección, en una hora | Reutilice cada token hasta que expire |
503 temporarily_unavailable | Intente de nuevo en breve | Reintentar con retroceso |
401 de /api | El token expiró o fue revocado | Solicite un nuevo token una vez, luego deténgase |
403 forbidden al gestionar clientes | Falta autoridad de identidad, una pertenencia actual al proyecto con la capacidad project o el rol de administrador de la organización de la persona responsable | Pida a la persona invitada que acepte la inscripción; confirme el acceso Gestionar a la identidad, la autorización Gestionar del agente en el proyecto y el rol de administrador de la organización de la persona responsable |
403 insufficient_access de /api | El nivel de acceso del token no puede hacer ese cambio, o el proyecto requiere revisión para cambios de agente | Use un cliente Manage; mientras el proyecto requiere revisión, los cambios en listas de reproducción y pantallas van a Revisiones |
402 payment_required de /api | El proyecto no tiene crédito para una solicitud pagada | Agregar crédito al proyecto |