サーバーサイドの統合

ニュース メディアは主に、読者とその利用資格を管理するためにサーバーサイドの統合を使用します。主に、UpdateReaderEntitlements を使用して PPID に使うプロダクト ID の利用資格に関する Google の記録を更新します。

GCP の設定

GCP で Subscription Linking API を有効にする

サービス アカウントを使用して読者の利用資格を管理するには、GCP プロジェクトで Subscription Linking API を有効にして、OAuth サービス アカウントを適切に構成する必要があります。プロジェクトの Subscription Linking API を有効にするには、メニュー -> [API とサービス] -> [ライブラリ] と移動して Subscription Linking を検索するか、ページに直接アクセスしてください。


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

API

図 1. API ライブラリに移動し、GCP プロジェクトの API を有効にする。

GCP でサービス アカウントを作成する

サービス アカウントは、アプリケーションから Subscription Linking API へのアクセスを許可するために使用されます。

  1. GCP プロジェクトのコンソール内でサービス アカウントを作成します
  2. サービス アカウントの認証情報を作成し、アプリケーションにアクセス可能で安全な場所に credentials.json ファイルを保存します。

Subscription Linking API でサービス アカウントを使用する

サービス アカウントを作成して credentials.json ファイルを生成したら、Google API クライアント ライブラリか、REST API を介した署名付きリクエストを利用できます。クライアント ライブラリは適切な access_token のリクエストを自動的に処理します。同時に、REST インターフェースではリクエストと一緒に送信するため、リクエストに署名して id_tokenaccess_token とを交換する必要があります。次のクライアント ライブラリと REST API は、どちらも getReader() エンドポイントを使用します。API メソッド全般のライブデモについては、定期購入リンクのデモ版サイト(コード)をご覧ください。

Node.js googleapis クライアント ライブラリを使用したリクエストの例

import subscriptionLinking from '@googleapis/readerrevenuesubscriptionlinking'

const auth = new subscriptionLinking.auth.GoogleAuth({
  keyFile: process.env.PATH_TO_CREDENTIALS_LOCATION,
  scopes: [
    'https://www.googleapis.com/auth/readerrevenue.subscriptionlinking.manage'
  ]
})

const client = subscriptionLinking.readerrevenuesubscriptionlinking(
  {
    version: 'v1',
    auth
  }
)

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

REST API リクエストへの手動署名

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
}