Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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()
@upbit
Copy link

upbit commented Feb 15, 2021

Thank you very much for this script, this is currently the easiest way to get OAuth2 token.
Open the chrome network tab and click login. The last red url contains code:

@emesh0620
Copy link

emesh0620 commented Feb 16, 2021

Thank you very much. I couldn't log in temporarily,
but I copied and pasted the source code and it worked.
It's a shame that I can't really log in with a password, but I found some hope.

@Xpl0itR
Copy link

Xpl0itR commented Feb 16, 2021

Works perfect 👌 thanks

@shibababa
Copy link

shibababa commented Feb 16, 2021

great.
That was a really big help.
thanks.

@Xpl0itR
Copy link

Xpl0itR commented Feb 16, 2021

One criticism i have is that instead of printing expires_in you should instead print the timestamp of when it expires

@TakaShirowa
Copy link

TakaShirowa commented Feb 19, 2021

requests.exceptions.SSLError: HTTPSConnectionPool(host='oauth.secure.pixiv.net', port=443): Max retries exceeded with url: /auth/token (Caused by SSLError(SSLError(1, '[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1122)')
))
I keep reporting this error, is it problem to the network?

@bakashigure
Copy link

bakashigure commented Feb 19, 2021

requests.exceptions.SSLError: HTTPSConnectionPool(host='oauth.secure.pixiv.net', port=443): Max retries exceeded with url: /auth/token (Caused by SSLError(SSLError(1, '[SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:1122)')
))
I keep reporting this error, is it problem to the network?

add proxy here
3%{((EE}%}%CCCUPZ2CJ0

@TakaShirowa
Copy link

TakaShirowa commented Feb 19, 2021

requests.exceptions.SSLError:HTTPSConnectionPool(host ='oauth.secure.pixiv.net',端口= 443):url超过了最大重试次数:/ auth / token(由SSLError(SSLError(1,'[SSL:WRONG_VERSION_NUMBER]版本号错误(_ssl.c:1122)')
))
我一直在报告此错误,这对网络有问题吗?

在此处添加代理
3%{(((EE}%}%CCCUPZ2CJ0

Problem solved, thank you

@Cai-Zhenhui
Copy link

Cai-Zhenhui commented Mar 8, 2021

After I get the Code and input it, the following exception is thrown:
File ".\pixiv_auth.py", line 69, in login response = requests.post( ... File "C:\Users\MACHENIKE\AppData\Local\Programs\Python\Python38\lib\site-packages\requests\adapters.py", line 498, in send raise ConnectionError(err, request=request) requests.exceptions.ConnectionError: ('Connection aborted.', ConnectionResetError(10054, 'An existing connection was forcibly closed by the remote host', None, 10054, None))
How should I do?

@railannad
Copy link

railannad commented Mar 9, 2021

My Python Version is 3.8.0 and how should I do?
image

@ZipFile
Copy link
Author

ZipFile commented Mar 9, 2021

@Cai-Zhenhui check your connection to pixiv. Maybe you need a proxy, as suggested by bakashigure above.

@railannad this message appears when your code is invalid, expired or was already used. Try again.

@railannad
Copy link

railannad commented Mar 9, 2021

@Cai-Zhenhui check your connection to pixiv. Maybe you need a proxy, as suggested by bakashigure above.

@railannad this message appears when your code is invalid, expired or was already used. Try again.

I tried again and successed . Thank you very much

@koitoyuu19
Copy link

koitoyuu19 commented Mar 10, 2021

After I input Code and hit the enter key, nothing display. So I add proxy 127.0.0.1:7890,but it shows like this. Could you help me ? please.
7RC4%JQNV}0BZP VXU~D K3

@Thesola10
Copy link

Thesola10 commented Jun 30, 2021

To devs who wish to use this method to access the pixiv API: You can automate the login process for the end user!

@KrisTheNewest
Copy link

KrisTheNewest commented Jul 22, 2021

anyone knows what scale expires_in uses?

@ZipFile
Copy link
Author

ZipFile commented Jul 22, 2021

Seconds.

@KrisTheNewest
Copy link

KrisTheNewest commented Jul 22, 2021

so the key expires within an hour? talk about inconvenience, lol

@ZipFile
Copy link
Author

ZipFile commented Jul 22, 2021

Refresh can be automated, though.

@KrisTheNewest
Copy link

KrisTheNewest commented Jul 27, 2021

I tried porting/reverse engineering your py script to js and I get invalid_grant error.
image

@ZipFile
Copy link
Author

ZipFile commented Jul 28, 2021

You need to submit it as a form data. axios for nodejs does not support it out of the box.

@eggplants
Copy link

eggplants commented Aug 28, 2021

I have made this script more easier to run and available from another program. Also I have prepared a headless mode so it can work in environments without GUI.
Install: pip install gppt
See: https://github.com/eggplants/get-pixivpy-token

@enricocaliolo
Copy link

enricocaliolo commented Sep 1, 2021

I can't get my token. It always give me this same error. I already tried several times, but it doesn't work. I did what @upbit said, trying to get the code from the console. If I have to send some other things to clarify something, just let me know.

@ZipFile
Copy link
Author

ZipFile commented Sep 1, 2021

&via=login is not part of the code. Remove it.

@enricocaliolo
Copy link

enricocaliolo commented Sep 1, 2021

thank you, sir! Now that I have the access_token and refresh_token, what should I do to authenticate and start making requests? I tried a few things based on the documentation but I got a few errors:
image ( I tried this)

image ( and got these errors)

@DITlieD
Copy link

DITlieD commented Nov 4, 2021

enricocaliolo, did u find the solution ? im with the same error ;-;

@enricocaliolo
Copy link

enricocaliolo commented Nov 4, 2021

enricocaliolo, did u find the solution ? im with the same error ;-;

unfortunately, no. I think either the wrapper library is broken or Pixiv doesn't allow this kind of authentication. What I did was learn BeautifulSoup and Selenium to scrape Pixiv, and it worked perfectly. Unless they update it and adress the error (which is in the issues), I think you are better off learning web scraping really

@BluerayDisc
Copy link

BluerayDisc commented Nov 9, 2021

error:
{'error': 'invalid_request',
'errors': {'system': {'code': 918, 'message': '不正なOAuthクライアントです'}},
'has_error': True}
Can you tell me what's wrong with it?;-;

@eggplants
Copy link

eggplants commented Nov 9, 2021

@BluerayDisc
See forked gist of this pages by author of pixivpy: https://gist.github.com/upbit/6edda27cb1644e94183291109b8a5fde

@DITlieD
Copy link

DITlieD commented Nov 10, 2021

enricocaliolo, did u find the solution ? im with the same error ;-;

unfortunately, no. I think either the wrapper library is broken or Pixiv doesn't allow this kind of authentication. What I did was learn BeautifulSoup and Selenium to scrape Pixiv, and it worked perfectly. Unless they update it and adress the error (which is in the issues), I think you are better off learning web scraping really

Hmm, ok, thank you !

@540300286
Copy link

540300286 commented Dec 26, 2021

$ python pixiv_auth.py refresh OLD_REFRESH_TOKEN

error:
{'error': 'invalid_grant',
'errors': {'system': {'code': 1508, 'message': 'Invalid refresh token'}},
'has_error': True}

@RyouMon
Copy link

RyouMon commented Jan 20, 2022

This is a suggestion: set a timeout on requests.post() method.

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