search for standard sites pub-search.waow.tech
search zig blog atproto
11
fork

Configure Feed

Select the types of activity you want to include in your feed.

chore(oauth): add auth debug endpoint + session resolution logging

- /api/auth-debug returns {hasCookieHeader, hasSessionCookie, sessionTokenPrefix, origin, didResolved, frontendOrigin} so we can see what the browser is sending cross-origin
- logfire.info on callback when session is stored + cookie set
- logfire.debug / warn in getSessionDid to distinguish between
"no cookie at all", "cookie but no pubsearch_session", and "token
present but no live session"

Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>

+62 -1
+60 -1
backend/src/oauth.zig
··· 20 20 const zat = @import("zat"); 21 21 const zat_oauth = zat.oauth; 22 22 const store = @import("state.zig"); 23 + const logfire = @import("logfire"); 23 24 24 25 // `transition:chat.bsky` grants access to chat.bsky.* xrpc endpoints 25 26 // (proxied through the user's PDS to did:web:api.bsky.chat). needed so ··· 830 831 return; 831 832 }; 832 833 store.deleteAuthRequest(state); 834 + logfire.info("oauth.callback: session stored did={s} handle={s}", .{ auth_req.did, auth_req.handle }); 833 835 834 836 // redirect back to the subscriptions page with ?logged_in={handle} 835 837 var redirect_url: std.ArrayList(u8) = .empty; ··· 856 858 return; 857 859 }; 858 860 861 + logfire.info("oauth.callback: setting cookie redirect={s}", .{redirect_url.items}); 859 862 try request.respond("", .{ 860 863 .status = .found, 861 864 .extra_headers = &.{ ··· 892 895 // --------------------------------------------------------------------------- 893 896 894 897 pub fn getSessionDid(request: *http.Server.Request) ?[]const u8 { 898 + var saw_cookie_header = false; 899 + var saw_token = false; 895 900 var it = request.iterateHeaders(); 896 901 while (it.next()) |h| { 897 902 if (std.ascii.eqlIgnoreCase(h.name, "cookie")) { 903 + saw_cookie_header = true; 898 904 const token = parseCookieValue(h.value, "pubsearch_session") orelse continue; 899 - return store.resolveSessionToken(token); 905 + saw_token = true; 906 + const did = store.resolveSessionToken(token); 907 + if (did) |d| { 908 + logfire.debug("getSessionDid: resolved did={s}", .{d}); 909 + return d; 910 + } 911 + logfire.warn("getSessionDid: token present but no session found (token prefix={s})", .{token[0..@min(token.len, 8)]}); 912 + return null; 900 913 } 901 914 } 915 + if (!saw_cookie_header) { 916 + logfire.debug("getSessionDid: no Cookie header present on request", .{}); 917 + } else if (!saw_token) { 918 + logfire.debug("getSessionDid: Cookie header present but pubsearch_session missing", .{}); 919 + } 902 920 return null; 921 + } 922 + 923 + /// Diagnostic: dump which auth-related headers / cookies are reaching the 924 + /// backend. Reveals nothing sensitive — just whether the cookie made the trip. 925 + pub fn handleAuthDebug(request: *http.Server.Request) !void { 926 + var arena = std.heap.ArenaAllocator.init(std.heap.smp_allocator); 927 + defer arena.deinit(); 928 + const alloc = arena.allocator(); 929 + 930 + var has_cookie_header = false; 931 + var has_session_cookie = false; 932 + var session_token_prefix: []const u8 = ""; 933 + var origin_hdr: []const u8 = ""; 934 + 935 + var it = request.iterateHeaders(); 936 + while (it.next()) |h| { 937 + if (std.ascii.eqlIgnoreCase(h.name, "cookie")) { 938 + has_cookie_header = true; 939 + if (parseCookieValue(h.value, "pubsearch_session")) |tok| { 940 + has_session_cookie = true; 941 + session_token_prefix = tok[0..@min(tok.len, 8)]; 942 + } 943 + } else if (std.ascii.eqlIgnoreCase(h.name, "origin")) { 944 + origin_hdr = h.value; 945 + } 946 + } 947 + 948 + const did_resolved: []const u8 = if (getSessionDid(request)) |d| d else ""; 949 + 950 + const body = try std.fmt.allocPrint(alloc, 951 + \\{{"hasCookieHeader":{s},"hasSessionCookie":{s},"sessionTokenPrefix":"{s}","origin":"{s}","didResolved":"{s}","frontendOrigin":"{s}"}} 952 + , .{ 953 + if (has_cookie_header) "true" else "false", 954 + if (has_session_cookie) "true" else "false", 955 + session_token_prefix, 956 + origin_hdr, 957 + did_resolved, 958 + cfg.frontend_origin, 959 + }); 960 + 961 + try sendJson(request, body); 903 962 } 904 963 905 964 fn parseCookieValue(cookie_header: []const u8, name: []const u8) ?[]const u8 {
+2
backend/src/server.zig
··· 106 106 try oauth.handleCallback(request); 107 107 } else if (mem.eql(u8, path, "/oauth/logout") and request.head.method == .POST) { 108 108 try oauth.handleLogout(request); 109 + } else if (mem.eql(u8, path, "/api/auth-debug")) { 110 + try oauth.handleAuthDebug(request); 109 111 } else if (mem.eql(u8, path, "/api/me")) { 110 112 try subs.handleMe(request, io); 111 113 } else if (mem.eql(u8, path, "/api/my-publications")) {