Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle resolution error for bsky.social handles #2926

Closed
TylerFisher opened this issue Oct 30, 2024 · 4 comments
Closed

Handle resolution error for bsky.social handles #2926

TylerFisher opened this issue Oct 30, 2024 · 4 comments
Labels
bug Something isn't working

Comments

@TylerFisher
Copy link

TylerFisher commented Oct 30, 2024

Describe the bug

I'm working on implementing OAuth using oauth-client-node, and I'm having trouble with handle resolution, which as I understand that package handles internally. When I try to resolve a handle verified through DNS records (e.g. mine: @tylerjfisher.com), everything works.

When I try to resolve a standard bsky.social handle, I get an OAuthResolverError. In my request logs, I can see outbound requests made to <username>.bsky.social/.well-known/atproto-did, which seem to resolve correctly, but I'm not ending up with the DID.

If I implement handle resolution on my own through @atproto/identity, before I call authorize, I can successfully retrieve the DID and pass that to the authorize endpoint. But then the login form on bsky.social uses the DID, which will definitely be confusing for users.

After following the traceback, this is what is failing in the atproto package.

To Reproduce

Steps to reproduce the behavior:

  1. Implement oauth-client-node according to examples in documentation
  2. Try to begin OAuth handshake with bsky.social handle

Expected behavior

I expect that I would get to the bsky.social OAuth login screen with the user's handle populated in the form.

Details

  • Operating system: Ubuntu, I assume? Only happening in production.
  • Node version: 20

Additional context

This problem is happening in a serverless deployed environment on Vercel.

Here is the full traceback:

OAuthResolverError: Failed to resolve identity: sillapp.bsky.social
    at OAuthResolverError.from (/var/task/node_modules/@atproto/oauth-client/dist/oauth-resolver-error.js:11:16)
    at OAuthResolver.resolveIdentity (/var/task/node_modules/@atproto/oauth-client/dist/oauth-resolver.js:76:64)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async OAuthResolver.resolveFromIdentity (/var/task/node_modules/@atproto/oauth-client/dist/oauth-resolver.js:66:26)
    ... 4 lines matching cause stack trace ...
    at async callLoaderOrAction (/var/task/node_modules/@remix-run/router/dist/router.cjs.js:4785:16)
    at async Promise.all (index 1) {
  [cause]: TypeError: Handle "sillapp.bsky.social" does not resolve to a DID
      at IdentityResolver.getDocumentFromHandle (/var/task/node_modules/@atproto-labs/identity-resolver/dist/identity-resolver.js:41:19)
      at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
      at async IdentityResolver.resolve (/var/task/node_modules/@atproto-labs/identity-resolver/dist/identity-resolver.js:24:15)
      at async OAuthResolver.resolveIdentity (/var/task/node_modules/@atproto/oauth-client/dist/oauth-resolver.js:73:20)
      at async OAuthResolver.resolveFromIdentity (/var/task/node_modules/@atproto/oauth-client/dist/oauth-resolver.js:66:26)
      at async NodeOAuthClient.authorize (/var/task/node_modules/@atproto/oauth-client/dist/oauth-client.js:152:40)
      at async action$6 (file:///var/task/build/server/nodejs-eyJydW50aW1lIjoibm9kZWpzIn0/index.js:3931:17)
      at async Object.callRouteAction (/var/task/node_modules/@remix-run/server-runtime/dist/data.js:36:16)
      at async /var/task/node_modules/@remix-run/router/dist/router.cjs.js:4719:19
      at async callLoaderOrAction (/var/task/node_modules/@remix-run/router/dist/router.cjs.js:4785:16)
}

And my client metadata:

{
  "redirect_uris": [
    "https://sill.social/bluesky/auth/callback"
  ],
  "response_types": [
    "code"
  ],
  "grant_types": [
    "authorization_code",
    "refresh_token"
  ],
  "scope": "atproto transition:generic",
  "token_endpoint_auth_method": "private_key_jwt",
  "token_endpoint_auth_signing_alg": "ES256",
  "jwks_uri": "https://sill.social/jwks.json",
  "application_type": "web",
  "client_id": "https://sill.social/client-metadata.json",
  "client_name": "Sill",
  "client_uri": "https://sill.social",
  "dpop_bound_access_tokens": true
}

And my action calling authorize:

export const action = async ({ request }: ActionFunctionArgs) => {
	const userId = await requireUserId(request);
	const data = await request.formData();
	const handle = data.get("handle");
	if (typeof handle !== "string") {
		throw new Error("Invalid handle");
	}
	const state = JSON.stringify({ userId, handle });
	const oauthClient = await createOAuthClient();
	try {
		const url = await oauthClient.authorize(handle, {
			scope: "atproto transition:generic",
			state,
		});
		return redirect(url.toString());
	} catch (error) {
		if (error instanceof OAuthResponseError) {
			const url = await oauthClient.authorize(handle, {
				scope: "atproto transition:generic",
				state,
			});
			return redirect(url.toString());
		}
		throw error;
	}
};
@TylerFisher TylerFisher added the bug Something isn't working label Oct 30, 2024
@TylerFisher
Copy link
Author

This was an issue with Remix and Vercel, not Atproto. Nevermind!

@dliebner
Copy link

Wait what was the issue? I'm getting the same thing, "Failed to resolve identity" for everything

@TylerFisher
Copy link
Author

I don't know if you're in the same infrastructure scenario that I was, but it was related to Remix, its new Single Fetch feature, and how Vercel handles it. vercel/remix#109

@dliebner
Copy link

Ah, thank you. The issue for me was actually that the abort controller from the sample code was triggering and masking the actual error I should have been getting. I had added in the req.complete check here to prevent aborting completed requests:

const ac = new AbortController();
req.on('close', () => req.complete || ac.abort());

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants