psn-api

repository·main·Indexed 19 days ago

https://github.com/achievements-app/psn-api

A modular JavaScript/TypeScript library for fetching trophy, user, and game data from the PlayStation Network. Compatible with Node.js (v20+) and browser environments, it provides tools for authentication via NPSSO tokens, GraphQL query entrypoints, and comprehensive data models for PSN entities.

Tokens
31.7K
Snippets
68
Records
103
Agent score
61%

What's inside psn-api

  1. Overview of psn-api features and design philosophy

    main

    Overview

    psn-api is a JavaScript library designed to retrieve trophy, user, and game data from the PlayStation Network.

    Key Features

    • Lightweight: The library is less than 3Kb in size.
    • Zero Configuration: No setup or configuration is required to start using the functions.
    • TypeScript Support: Built-in TypeScript support is available out of the box.
    • High Test Coverage: The library maintains 100% test coverage.

    Design Philosophy: Low-level vs. High-level

    Unlike other PSN wrappers that provide high-level abstractions (where a single function call might trigger multiple hidden network requests), psn-api follows a low-level, UNIX-like approach:

    1. Single Responsibility: Each function performs exactly one API call. This makes it easier to compose complex logic by combining small, predictable building blocks.
    2. Resilience: Because functions are low-level, the library is easier to maintain and fix when Sony changes specific endpoints, without breaking entire high-level abstractions.
    3. Isolation: Functions work in isolation, allowing you to use only the specific parts of the library you need.
  2. How the refresh token usage flow works

    main

    Because psn-api access tokens are short-lived, you must implement a mechanism to refresh them using a refresh token to avoid requiring manual re-authentication (NPSSO) frequently.

    The workflow is as follows:

    1. Check Expiration: Before calling any psn-api function, check the expiresIn value (provided by exchangeAccessCodeForAuthTokens) to determine if your current accessToken has expired.
    2. Refresh if Necessary: If the token is expired, call exchangeRefreshTokenForAuthTokens() using your stored refreshToken to obtain a new set of tokens.
    3. Execute API Call: Use the newly acquired accessToken to perform your desired psn-api operation.

    Security Note: psn-api does not manage token storage. You are responsible for storing accessToken and refreshToken securely. Treat them as sensitive secrets. For single-user bots, a key-value store like Redis is sufficient; for multi-user applications, encrypt tokens using a secure algorithm like argon2id before storing them in a database.

  3. How the manual authentication flow works

    main

    The manual authentication flow is the most common method for authorizing requests to PSN's APIs. It involves a multi-step process of exchanging browser-based credentials for API-ready tokens.

    The flow steps are:

    1. Manual Sign-in: Sign in to the PlayStation website in a browser to establish session cookies.
    2. NPSSO Retrieval: Use those cookies to retrieve an npsso token.
    3. Access Code Exchange: Exchange the npsso token for an access code.
    4. Token Exchange: Exchange the access code for an access token (short-lived) and a refresh token (used to get new access tokens).

    Note: This method requires manual intervention approximately every two months to retrieve a new npsso token.

  4. Refresh your access token

    main

    To maintain a continuous session, you can use exchangeRefreshTokenForAuthTokens() to swap a refresh token for a new access token.

    When you first authenticate via exchangeAccessCodeForAuthTokens(), you receive an authorization object containing expiresIn (seconds). It is recommended to convert this into an ISO date string for easy storage and comparison. When the current time exceeds that expiration date, trigger the refresh flow.

    // 1. Initial authentication (from your first login)
    const authorization = await exchangeAccessCodeForAuthTokens(accessCode);
    
    // 2. Calculate expiration date for storage
    const now = new Date();
    const expirationDate = new Date(
      now.getTime() + authorization.expiresIn * 1000
    ).toISOString();
    
    // ... some time later ...
    
    // 3. Check if expired
    const isAccessTokenExpired = new Date(expirationDate).getTime() < now.getTime();
    
    if (isAccessTokenExpired) {
      // 4. Refresh the token
      // Returns an auth object with the same shape as exchangeAccessCodeForAuthTokens()
      const updatedAuthorization = await exchangeRefreshTokenForAuthTokens(
        authorization.refreshToken
      );
    
      // 5. Update your stored expiration date with updatedAuthorization.expiresIn
    }
  5. Retrieve your NPSSO token manually

    main

    To obtain the npsso token required for the authentication flow:

    1. Open a web browser and visit the PlayStation homepage.
    2. Click "Sign In" and log in with your PSN account credentials.
    3. In the same browser session, navigate to https://ca.account.sony.com/api/v1/ssocookie.
    4. Locate the JSON response containing the npsso key. The value is a 64-character token.

    If you receive an error response, try performing these steps in a different browser.

    { "npsso": "<64 character token>" }
  6. Obtain an authentication token using NPSSO

    main

    To use the API, you must first obtain an NPSSO token from your browser and exchange it for access and refresh tokens.

    1. Get your NPSSO token

    1. Log in to the PlayStation homepage in your web browser.
    2. Visit https://ca.account.sony.com/api/v1/ssocookie in the same browser.
    3. Copy the <64 character token> from the npsso field in the JSON response.

    2. Exchange NPSSO for Auth Tokens

    Use exchangeNpssoForAccessCode to get an access code, then use exchangeAccessCodeForAuthTokens to get the final authorization object containing your accessToken and refreshToken.

    // This is the value you copied from the previous step.
    const myNpsso = "<64 character token>";
    
    // We'll exchange your NPSSO for a special access code.
    const accessCode = await exchangeNpssoForAccessCode(myNpsso);
    
    // 🚀 We can use the access code to get your access token and refresh token.
    const authorization = await exchangeAccessCodeForAuthTokens(accessCode);
  7. Deploy the website to GitHub Pages

    main

    To build the website and push it to the gh-pages branch for GitHub Pages hosting, use the pnpm deploy command. You must provide your GitHub username via the GIT_USER environment variable and set USE_SSH=true.

    $ GIT_USER=<Your GitHub username> USE_SSH=true pnpm deploy
  8. How to obtain an authentication token

    main

    To use any endpoint function in the API, you must first be authorized by PSN. This involves obtaining an npsso token from your browser and exchanging it for access and refresh tokens.

    1. Obtain your NPSSO

    1. Visit https://www.playstation.com/, click "Sign In", and log in.
    2. In the same browser, visit https://ca.account.sony.com/api/v1/ssocookie.
    3. Copy the <64 character token> from the npsso field in the JSON response. Warning: This token is equivalent to your password; do not expose it publicly.

    2. Exchange NPSSO for Auth Tokens

    Use the following sequence of function calls to obtain an authorization object containing an accessToken and refreshToken.

    3. Use the Access Token

    Every endpoint function requires an object containing your accessToken as its first argument.

    // 1. The value copied from the browser step
    const myNpsso = "<64 character token>";
    
    // 2. Exchange NPSSO for an access code
    const accessCode = await exchangeNpssoForAccessCode(myNpsso);
    
    // 3. Exchange access code for access and refresh tokens
    const authorization = await exchangeAccessCodeForAuthTokens(accessCode);
    
    // 4. Use the token to call an endpoint
    const userTitlesResponse = await getUserTitles(
      { accessToken: authorization.accessToken },
      "me"
    );