Toegangsrechten van gebruikers synchroniseren (integratie aan de serverzijde)

Uitgevers gebruiken voornamelijk integratie aan de serverzijde om lezers en hun toegangsrechten te beheren. Ze gebruiken hoofdzakelijk UpdateReaderEntitlements om het Google-record van een Product ID-toegangsrecht voor een PPID te updaten.

Google Cloud configureren

Het configureren van de abonnementskoppeling in Google Cloud bestaat uit 2 belangrijke componenten:

  1. De API aanzetten voor een bepaald project
  2. Een serviceaccount maken voor toegang tot de API

De Subscription Linking API aanzetten

Als je een serviceaccount wilt gebruiken en de toegangsrechten van een lezer wilt beheren, moet een Google Cloud-project een correct geconfigureerde OAuth-serviceaccount hebben en moet de Subscription Linking API aanstaan. Als je de Subscription Linking API wilt aanzetten voor een project, ga je vanuit het menu naar -> API's en services -> Bibliotheek en zoek je naar Subscription Linking of ga je rechtstreeks naar de pagina:


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

api

Afbeelding 1. Navigeren naar de API-bibliotheek en de API aanzetten voor een Google Cloud-project.

Een serviceaccount maken

Serviceaccounts worden gebruikt om toegang te geven vanuit je app tot de Subscription Linking API.

  1. Maak een serviceaccount in de console van je project.
  2. Maak inloggegevens voor het serviceaccount en sla het credentials.json-bestand op een beveiligde locatie op die toegankelijk is voor je app.
  3. Ken de IAM-rol 'Beheerder van abonnementen koppelen' toe aan de serviceaccount die je hebt gemaakt. Voor een gedetailleerde controle over de mogelijkheden van de serviceaccount, kun je de juiste rol toewijzen uit de volgende tabel.
Functionaliteit / Rol Beheerder van de abonnementskoppeling Viewer abonnementskoppeling Viewer toegangsrechten abonnementskoppeling
Lezersrechten ophalen
Lezers ophalen
Lezersrechten updaten
Lezers verwijderen

Serviceaccounts gebruiken met de Subscription Linking API

Gebruik serviceaccounts om aanroepen van de Subscription Linking API te verifiëren, via de clientbibliotheek van googleapis of door verzoeken te ondertekenen via de REST API. Clientbibliotheken zorgen automatisch voor het opvragen van de juiste access_token terwijl de REST API eerst een id_token opvraagt en deze dan inwisselt voor een access_token.

De volgende voorbeelden van een clientbibliotheek en REST API gebruiken beide het getReader()-eindpunt. Voor een live demonstratie van alle API-methoden raadpleeg je de site van de Demo voor het koppelen van abonnementen of de code.

Voorbeeldverzoek met de clientbibliotheek node.js googleapis

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
  });
};

REST API-verzoeken handmatig ondertekenen

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
}