Skip to content

Instantly share code, notes, and snippets.

@ZipFile
Last active March 18, 2025 15:12
Show Gist options
  • Save ZipFile/c9ebedb224406f4f11845ab700124362 to your computer and use it in GitHub Desktop.
Save ZipFile/c9ebedb224406f4f11845ab700124362 to your computer and use it in GitHub Desktop.
Pixiv OAuth Flow

Retrieving Auth Token

  1. Run the command:

    python pixiv_auth.py login

    This will open the browser with Pixiv login page.

  2. Open dev console (F12) and switch to network tab.

  3. Enable persistent logging ("Preserve log").

  4. Type into the filter field: callback?

  5. Proceed with Pixiv login.

  6. After logging in you should see a blank page and request that looks like this: https://app-api.pixiv.net/web/v1/users/auth/pixiv/callback?state=...&code=.... Copy value of the code param into the pixiv_auth.py's prompt and hit the Enter key.

If you did everything right and Pixiv did not change their auth flow, pair of auth_token and refresh_token should be displayed.

⚠️ code's lifetime is extremely short, so make sure to minimize delay between step 5 and 6. Otherwise, repeat everything starting step 1.

Refresh Tokens

python pixiv_auth.py refresh OLD_REFRESH_TOKEN
#!/usr/bin/env python
from argparse import ArgumentParser
from base64 import urlsafe_b64encode
from hashlib import sha256
from pprint import pprint
from secrets import token_urlsafe
from sys import exit
from urllib.parse import urlencode
from webbrowser import open as open_url
import requests
# Latest app version can be found using GET /v1/application-info/android
USER_AGENT = "PixivAndroidApp/5.0.234 (Android 11; Pixel 5)"
REDIRECT_URI = "https://app-api.pixiv.net/web/v1/users/auth/pixiv/callback"
LOGIN_URL = "https://app-api.pixiv.net/web/v1/login"
AUTH_TOKEN_URL = "https://oauth.secure.pixiv.net/auth/token"
CLIENT_ID = "MOBrBDS8blbauoSck0ZfDbtuzpyT"
CLIENT_SECRET = "lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj"
def s256(data):
"""S256 transformation method."""
return urlsafe_b64encode(sha256(data).digest()).rstrip(b"=").decode("ascii")
def oauth_pkce(transform):
"""Proof Key for Code Exchange by OAuth Public Clients (RFC7636)."""
code_verifier = token_urlsafe(32)
code_challenge = transform(code_verifier.encode("ascii"))
return code_verifier, code_challenge
def print_auth_token_response(response):
data = response.json()
try:
access_token = data["access_token"]
refresh_token = data["refresh_token"]
except KeyError:
print("error:")
pprint(data)
exit(1)
print("access_token:", access_token)
print("refresh_token:", refresh_token)
print("expires_in:", data.get("expires_in", 0))
def login():
code_verifier, code_challenge = oauth_pkce(s256)
login_params = {
"code_challenge": code_challenge,
"code_challenge_method": "S256",
"client": "pixiv-android",
}
open_url(f"{LOGIN_URL}?{urlencode(login_params)}")
try:
code = input("code: ").strip()
except (EOFError, KeyboardInterrupt):
return
response = requests.post(
AUTH_TOKEN_URL,
data={
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"code": code,
"code_verifier": code_verifier,
"grant_type": "authorization_code",
"include_policy": "true",
"redirect_uri": REDIRECT_URI,
},
headers={"User-Agent": USER_AGENT},
)
print_auth_token_response(response)
def refresh(refresh_token):
response = requests.post(
AUTH_TOKEN_URL,
data={
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
"grant_type": "refresh_token",
"include_policy": "true",
"refresh_token": refresh_token,
},
headers={"User-Agent": USER_AGENT},
)
print_auth_token_response(response)
def main():
parser = ArgumentParser()
subparsers = parser.add_subparsers()
parser.set_defaults(func=lambda _: parser.print_usage())
login_parser = subparsers.add_parser("login")
login_parser.set_defaults(func=lambda _: login())
refresh_parser = subparsers.add_parser("refresh")
refresh_parser.add_argument("refresh_token")
refresh_parser.set_defaults(func=lambda ns: refresh(ns.refresh_token))
args = parser.parse_args()
args.func(args)
if __name__ == "__main__":
main()
@exabym
Copy link

exabym commented Feb 18, 2025

Since all public entities started giving me an error, I had to create one on my server.
This method still works, as of today.
Given that the instructions for the deployment are unclear, I used Podman from this post
The easiest way is to use Docker (or Podman)
1.Get a VM
2.Install Docker (or Podman)
3.Get an API token for Pixiv ( https://gist.github.com/ZipFile/c9ebedb224406f4f11845ab700124362 )
4.Start the RSSHub instance with
podman run --rm --replace --name rsshub -e PIXIV_REFRESHTOKEN=xxxxxxxxxxxx -p 1200:1200 -d docker.io/diygod/rsshub:chromium-bundled
5. Do security (firewalling, https (e.g. via Proxy), authentication) and auto updates for OS and docker (or podman)
Source of message

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment