Every OkLine request is signed with an X-Hmac header, so Node.js 18+ must be
on your PATH (OkLine runs a bundled WASM module through a tiny Node bridge to
compute the signature — see architecture). You also need
Python 3.9+.
There are three ways to get an authenticated OkLine:
- Reuse a saved session — log in once, then load the same file forever (this also restores your E2EE keys).
- QR-code login — scan a code with the LINE app, no password.
- E-mail + password — the classic RSA credential flow.
🔒 Tokens are credentials. An access token (and a saved session file) grants full access to your LINE account. Never commit, log, paste or share them. OkLine redacts them by default in recorded output, and
tokens.jsonis matched by the project.gitignore.
The easiest, most reliable pattern: log in once, save a session file, then load it on every later run. The session file keeps your access token, refresh token, certificate, mid — and the unwrapped E2EE (Letter Sealing) keychain — so encrypted messages keep working across runs without re-scanning a QR code.
from okline import OkLine
from okline.qrterm import print_qr
api = OkLine()
api.qr_login(on_qr=print_qr,
on_pin=lambda pin: print("Confirm this PIN on your phone:", pin))
api.save_tokens("tokens.json") # writes credentials + E2EE keychainapi.qr_login(...) (on the OkLine object) drives the QR flow and loads
your E2EE keys for this session, so a following save_tokens() persists them.
from okline import OkLine
api = OkLine.from_tokens_file("tokens.json") # restores tokens AND E2EE keys
print(api.get_profile())
print("E2EE ready:", api.e2ee.is_ready()) # True — encrypted chats workThat is all you need. Prefer this over hand-writing JSON — save_tokens /
from_tokens_file use the right field names and carry the E2EE keychain, which a
manual json.dump of {accessToken, refreshToken} cannot.
When a client is built with
from_tokens_file, OkLine auto-saves the file whenever the access token is refreshed (see Token refresh), so the stored session stays valid.
The CLI does exactly this for you: okline login logs in once and saves
./tokens.json; every other command reuses it automatically. See CLI.
Scan a QR with the LINE app on your phone — no password needed. OkLine renders the QR as ASCII right in your terminal and drives the whole flow:
from okline import OkLine
from okline.qrterm import print_qr
api = OkLine()
result = api.qr_login(
on_qr=lambda url: print_qr(url), # draw the QR (scan it)
on_pin=lambda pin: print("PIN:", pin), # show the PIN to confirm
wait_seconds=180, # how long to wait for you
)
print("logged in:", bool(result.access_token))
api.save_tokens("tokens.json") # so you don't have to scan again next timeWhat happens under the hood:
createSession → createQrCode → (generate a Curve25519 key inside the WASM)
→ show QR = callbackUrl + ?secret=<pubkey>&e2eeVersion=1
→ checkQrCodeVerified (you scan) → verifyCertificate / PIN flow
→ checkPinCodeVerified (you confirm the PIN) → qrCodeLoginV2 → tokens
The ?secret=…&e2eeVersion=1 on the QR URL is mandatory — without it the LINE
app shows "an error occurred" after scanning. OkLine generates the Curve25519
keypair inside the real ltsm.wasm and appends it automatically, so you only
render the URL on_qr hands you.
Light-background terminal? Pass print_qr(url, invert=True). QR garbled on
Windows? Run chcp 65001 first. For an inline graphical QR, install the extra:
pip install "okline[qr]".
qr_login returns a certificate. Save it and pass it next time to skip the PIN
step (verifyCertificate succeeds for a known device):
result = api.qr_login(on_qr=print_qr, certificate=saved_certificate)
result.certificateis also written into your session file bysave_tokens, so loading withfrom_tokens_filecarries it for you.
This mirrors the extension exactly: it fetches an RSA key, encrypts your
credentials and calls loginV2.
from okline import OkLine
api = OkLine()
result = api.auth.email_login("me@example.com", "secret", with_e2ee=False)
if result.success:
print("access token:", result.access_token[:12], "…")
print(api.get_profile())
elif result.type == 3: # REQUIRE_DEVICE_CONFIRM
print("Confirm this PIN on your phone:", result.pin_code)
else:
print("needs verification:", result.type, result.display_message)email_login returns a LoginResult with fields: .success, .type
(LoginResultType), .access_token, .refresh_token, .certificate, .mid,
.pin_code, .verifier, .display_message, .raw. On success the tokens are
adopted into the client automatically, so you can call API methods right away.
with_e2ee=True (the default) negotiates Letter Sealing (E2EE). The RSA password
blob is built and encrypted for you in
okline/crypto.py.
After a successful login you can persist the session the same way:
api.save_tokens("tokens.json")Automatic: if a refresh_token is set, a 401 from the server triggers a token
refresh and the original request is retried transparently. When the client was
built with from_tokens_file, the refreshed token is also written back to the
file.
You can also refresh manually:
new_access = api.auth.refresh_access_token()To build a client directly from tokens you already hold (auto-refresh enabled as soon as a refresh token is present):
api = OkLine(access_token="...", refresh_token="...")Invalidate the current session on the server:
api.auth.logout()From the CLI, okline logout does this and deletes the local tokens.json.
You can also remove the device from LINE app → Settings → Account → logged-in
devices.
See also: Getting started · Messaging · Receiving events / bots · CLI.