Skip to content

Commit 7fcabab

Browse files
new-usemamecrocodilestick
authored andcommitted
Fix Kobo sync failure with newer firmware: add OIDC discovery endpoint and fix OAuth routes (#82)
Newer Kobo firmware performs a full OIDC authentication flow before syncing. It calls /oauth/.well-known/openid-configuration expecting a standard OIDC discovery document. Without a dedicated handler, the catch-all /oauth/<path> route intercepts it and returns OAuth tokens instead, causing an infinite retry loop. Changes: - Add HandleOidcDiscovery() route for /oauth/.well-known/openid-configuration that returns a proper OIDC discovery document with issuer, token_endpoint, authorization_endpoint, etc. - Add /oauth/authorize route to HandleOauthRequest to prevent 308 redirect loop - Fix make_calibre_web_oauth_response() to return current_user.id instead of reading user_id from request body (which is always empty on GET requests) Tested on Kobo firmware 4.45.23640 behind an nginx reverse proxy. Co-authored-by: new-usemame <248195428+new-usemame@users.noreply.github.com>
1 parent 2c848a0 commit 7fcabab

1 file changed

Lines changed: 21 additions & 1 deletion

File tree

cps/kobo.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1300,7 +1300,7 @@ def make_calibre_web_oauth_response():
13001300
"token_type": "Bearer",
13011301
"expires_in": 3600,
13021302
"scope": content.get("scope", ""),
1303-
"user_id": content.get("user_id", ""),
1303+
"user_id": str(current_user.id) if current_user and not current_user.is_anonymous else content.get("user_id", ""),
13041304
# Include legacy field names used by some Kobo requests
13051305
"AccessToken": access_token,
13061306
"RefreshToken": refresh_token,
@@ -1322,8 +1322,28 @@ def HandleAuthRequest():
13221322
return make_calibre_web_auth_response()
13231323

13241324

1325+
1326+
@csrf.exempt
1327+
@kobo.route('/oauth/.well-known/openid-configuration', methods=['GET', 'POST'])
1328+
@requires_kobo_auth
1329+
def HandleOidcDiscovery():
1330+
base_url = url_for("kobo.HandleOauthRequest",
1331+
auth_token=get_auth_token(),
1332+
_external=True).rsplit("/oauth", 1)[0]
1333+
payload = {
1334+
'issuer': base_url,
1335+
'authorization_endpoint': base_url + '/oauth/authorize',
1336+
'token_endpoint': base_url + '/oauth/token',
1337+
'userinfo_endpoint': base_url + '/oauth/userinfo',
1338+
'response_types_supported': ['code'],
1339+
'subject_types_supported': ['public'],
1340+
'id_token_signing_alg_values_supported': ['RS256'],
1341+
}
1342+
return make_response(jsonify(payload))
1343+
13251344
@csrf.exempt
13261345
@kobo.route("/oauth/token", methods=["GET", "POST"])
1346+
@kobo.route("/oauth/authorize", methods=["GET", "POST"])
13271347
@kobo.route("/oauth/refresh", methods=["GET", "POST"])
13281348
@kobo.route("/oauth/<path:subpath>", methods=["GET", "POST"])
13291349
@requires_kobo_auth

0 commit comments

Comments
 (0)