Sincronizar derechos de usuario (integración del lado del servidor)

Los editores utilizan la integración del lado del servidor principalmente para gestionar a los lectores y sus derechos. Fundamentalmente, los editores usan UpdateReaderEntitlements para actualizar el registro de Google del derecho de ID de producto de un PPID.

Configuración de Google Cloud

La configuración de la vinculación de suscripciones en Google Cloud incluye dos componentes importantes:

  1. Habilitar la API en un proyecto concreto
  2. Crear una cuenta de servicio para acceder a la API

Habilitar la API Subscription Linking

Para usar una cuenta de servicio y gestionar los derechos de un lector, un proyecto de Google Cloud debe tener la API Subscription Linking habilitada y una cuenta de servicio de OAuth configurada correctamente. Para habilitar la API Subscription Linking en un proyecto, ve al menú -> APIs y servicios -> Biblioteca y busca Subscription Linking. También puedes visitar la página directamente:


https://console.cloud.google.com/apis/library?project=gcp_project_id

API

Imagen 1. Acceder a la biblioteca de APIs y habilitar la API en un proyecto de Google Could.

Crear una cuenta de servicio

Las cuentas de servicio se usan para permitir el acceso de tu aplicación a la API Subscription Linking.

  1. Crea una cuenta de servicio en la consola de tu proyecto.
  2. Crea las credenciales de la cuenta de servicio y almacena el archivo credentials.json en una ubicación segura a la que pueda acceder tu aplicación.
  3. Concede el rol de gestión de identidades y accesos "Administrador de vinculación de suscripciones" a la cuenta de servicio que has creado. Para tener un control más exhaustivo de las funciones de la cuenta de servicio, puedes asignar el rol correspondiente de la siguiente tabla.
Función/rol Administrador de vinculación de suscripciones Visor de vinculación de suscripciones Visor de derechos de vinculación de suscripciones
Obtener derechos de lectores
Obtener lectores
Actualizar derechos de lectores
Eliminar lectores

Usar cuentas de servicio con la API Subscription Linking

Utiliza las cuentas de servicio para autenticar las llamadas a la API Subscription Linking, ya sea con la biblioteca de cliente googleapis o mediante la firma de solicitudes con la API REST. Las bibliotecas de cliente gestionan automáticamente las solicitudes del access_token adecuado, mientras que la API REST requiere obtener un id_token e, inmediatamente a continuación, intercambiarlo por un access_token.

Tanto la biblioteca de cliente como la API REST de abajo usan el endpoint getReader(). Para una demostración en directo de todos los métodos de la API, visita el sitio Demostración de la vinculación de suscripciones o su código.

Solicitud de ejemplo con la biblioteca de cliente googleapis de Node.js

import {readerrevenuesubscriptionlinking_v1, Auth} from 'googleapis';
const subscriptionLinking = readerrevenuesubscriptionlinking_v1.Readerrevenuesubscriptionlinking;

class SubscriptionLinking {
  constructor() {
    this.auth = new Auth.GoogleAuth({
      keyFile: process.env.KEY_FILE,
      scopes: [
        'https://www.googleapis.com/auth/readerrevenue.subscriptionlinking.manage'
      ],
    })
  }

  init() {
    return new subscriptionLinking(
        {version: 'v1', auth: this.auth})
  }
}

const api = new SubscriptionLinking();
const client = api.init();

async function getReader(ppid) {
  const publicationId = process.env.PUBLICATION_ID;
  return await client.publications.readers.get({
    name: `publications/${publicationId}/readers/${ppid}`,
  });
};

async function updateEntitlements(ppid) {
  const publicationId = process.env.PUBLICATION_ID;
  const requestBody = {
    /*
    Refer to
    https://developers.google.com/news/subscribe/subscription-linking/appendix/glossary#entitlements_object
    */
    entitlements : [{
      product_id: `${publicationId}:basic`,
      subscription_token: 'abc1234',
      detail: 'This is our basic plan',
      expire_time: '2025-10-21T03:05:08.200564Z'
    }]
  };
  return await client.publications.readers.updateEntitlements({
    name: `publications/${publicationId}/readers/${ppid}/entitlements`,
    requestBody
  });
};

Firmar manualmente solicitudes a la API REST

import fetch from 'node-fetch'
import jwt from 'jsonwebtoken'

function getSignedJwt() {
  /*
    Either store the credentials string in an environmental variable
    Or implement logic to fetch it.
  */
  const key_file = process.env.CREDENTIALS_STRING

  const issueDate = new Date()
  const expireMinutes = 60
  const offsetInSeconds = issueDate.getTimezoneOffset() * 60000
  const expireDate = new Date(issueDate.getTime() + (expireMinutes * 60000))
  const iat = Math.floor((issueDate.getTime() + offsetInSeconds) / 1000)
  const exp = Math.floor((expireDate.getTime() + offsetInSeconds) / 1000)

  const token = {
    iss: key_file.client_email,
    iat,
    exp,
    aud: 'https://oauth2.googleapis.com/token',
    scope:'https://www.googleapis.com/auth/readerrevenue.subscriptionlinking.manage',
  }
  return jwt.sign(token, key_file.private_key, {
    algorithm: 'RS256',
    keyid: key_file.private_key_id,
  })
}

async function getAccessToken(signedJwt) {
  let body = new URLSearchParams();
  body.set('grant_type', 'urn:ietf:params:oauth:grant-type:jwt-bearer')
  body.set('assertion', signedJwt)
  const request = await fetch('https://oauth2.googleapis.com/token', {
    method: 'POST',
    headers: {'Content-Type': 'application/x-www-form-urlencoded'},
    body
  })

  const accessResponse = await accessFetch.json()
  return accessResponse.access_token
}

async function getReader(ppid) {
  const publicationId = process.env.PUBLICATION_ID
  const base_url = 'https://readerrevenuesubscriptionlinking.googleapis.com/v1'
  const endpoint = `${base_url}/publications/${publicationId}/readers/${ppid}`
  const signedJwt = await getSignedJwt()
  const accessToken = await getAccessToken(signedJwt)

  const reader = await fetch(endpoint, {
     method: 'GET',
     headers: {
       Authorization: `Bearer ${accessToken}`,
     },
   }).then((response) => {
    return response.json()
  })

  return reader
}