S256, and the library does the rest.
Verification status, 2026-09-18. All three snippets were run against production, not just read off each library’s docs:
What is not covered for any of them is the browser half — consent and the code exchange — since that needs a human. Those requests are verified separately against production in the raw HTTP walkthrough, so every leg of the flow is tested; just not end to end inside one library.
What every library needs
Whatever you are using, these are the settings. Everything else is that library’s own naming.Two hosts. The consent page is on
simkl.com; everything else is on api.simkl.com. A library that takes a single “base URL” will get one of them wrong — look for separate authorize and token settings.The three defaults that need changing
Most libraries work as-is. These three do not, and each fails in a way that does not obviously point at the cause.Node.js — openid-client v6
algorithm: "oauth2" (the default is oidc, that path returns 404, and openid-client does not then try the OAuth 2.0 one), and the client auth method above.
Python — Authlib
Discovery lives on the framework integrations, which share one API — swapflask_client for django_client or starlette_client.
The plain
OAuth2Session from authlib.integrations.requests_client does not read metadata. It has no discovery support, so set authorization_endpoint and token_endpoint yourself there. server_metadata_url is a registry option, not a session attribute.Java — Spring Security
ClientRegistrations.fromIssuerLocation() walks three discovery paths in order, and ours — /.well-known/oauth-authorization-server — is the third; the two OpenID Connect paths ahead of it return 404, which is a 4xx, so Spring falls through to ours and configures itself. Setting authorization-uri and token-uri explicitly instead is never wrong, and is what you want if you would rather not depend on a network fetch at startup.
If you configured a client-secret, you also need:
code_challenge, the authorize request is rejected, and the error arrives on your callback rather than at the point of configuration — which makes it look like a redirect problem.
Anything else
If your library is not listed, it almost certainly works — fill in the table at the top and check three things:- PKCE is on, and set to
S256. This is where most failures start, because many libraries treat PKCE as opt-in for clients that have a secret. - The client auth method matches your registration. An app with no secret must send only
client_id; sending an empty secret is a different thing and fails. - The two hosts are not collapsed into one. Authorize is on
simkl.com, token is onapi.simkl.com.
See also
OAuth flow
The raw requests, and a dependency-free script that runs the whole flow.
Discovery
The RFC 8414 document, and the one flag some libraries need.
PKCE in AUTH V2
Generating the pair correctly, in five languages.
V1 client libraries
The tested V1 matrix. Note its discovery warning does not apply to V2.