Documentación

Asigne a servidores y trabajos de CI su propio acceso

Un cliente de servicio es un servidor, script o trabajo CI que trabaja en un proyecto con sus propias credenciales. Inicia sesión con una clave privada o un secreto, recibe un token de acceso de 15 minutos y nunca necesita que una persona apruebe cada ejecución.

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, reports y project, 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.pem

Tambié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.pem

Para 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_credentials

Con 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:

CampoValor
Encabezado algEdDSA, ES256 o RS256, coincidiendo con la clave
Encabezado kidEl id de la clave registrada
iss y subEl id del cliente.
audhttps://api.screenrig.ai o https://api.screenrig.ai/oauth/token, como una sola cadena
iat, expMáximo 5 minutos de diferencia
jtiUn 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:read o access:propose da al token un nivel inferior al del cliente, y los nombres de capacidades mantienen solo esas capacidades, por ejemplo scope=access:read reports. Un alcance más allá del cliente es invalid_scope.
  • resource: https://api.screenrig.ai/api, el predeterminado, para la API REST, o https://api.screenrig.ai/mcp para 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 list

Use --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

ParaPanel (Acceso, el cliente)CLI
Agregar una segunda claveAgregar clavescreenrig service-client add-key scl_ID --key-file new.pem
Eliminar una claveEliminar clavescreenrig service-client remove-key scl_ID --kid KID
Agregar un segundo secretoGenerar secretoscreenrig service-client add-secret scl_ID --secret-file new-secret
Eliminar un secretoEliminar secretoscreenrig service-client remove-secret scl_ID --secret-id css_ID
Cambiar acceso o capacidadesAcceso, luego Guardar accesoUse el dashboard
Finalizar el clienteRevocarscreenrig 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

RespuestaCausaCorregir
401 invalid_clientSecreto incorrecto o eliminado, una afirmación mala o repetida, un kid desconocido, un cliente revocado o un proyecto cancelado o eliminadoVerifique las credenciales contra service-client show; envíe un jti nuevo cada vez
400 invalid_scopeUn alcance más allá del acceso o capacidades del clienteSolicite menos o cambie el cliente
400 invalid_targetUn resource distinto a los dos listadosUse el predeterminado o el servidor remoto
429 rate_limitedMás de 600 tokens por cliente, o 1,200 solicitudes de token por dirección, en una horaReutilice cada token hasta que expire
503 temporarily_unavailableIntente de nuevo en breveReintentar con retroceso
401 de /apiEl token expiró o fue revocadoSolicite un nuevo token una vez, luego deténgase
403 forbidden al gestionar clientesFalta autoridad de identidad, una pertenencia actual al proyecto con la capacidad project o el rol de administrador de la organización de la persona responsablePida 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 /apiEl nivel de acceso del token no puede hacer ese cambio, o el proyecto requiere revisión para cambios de agenteUse 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 /apiEl proyecto no tiene crédito para una solicitud pagadaAgregar crédito al proyecto