UNPKG

@atproto/oauth-client

Version:

OAuth client for ATPROTO PDS. This package serves as common base for environment-specific implementations (NodeJS, Browser, React-Native).

113 lines 5.07 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.OAuthResolver = void 0; const oauth_types_1 = require("@atproto/oauth-types"); const oauth_resolver_error_js_1 = require("./oauth-resolver-error.js"); class OAuthResolver { constructor(identityResolver, protectedResourceMetadataResolver, authorizationServerMetadataResolver) { Object.defineProperty(this, "identityResolver", { enumerable: true, configurable: true, writable: true, value: identityResolver }); Object.defineProperty(this, "protectedResourceMetadataResolver", { enumerable: true, configurable: true, writable: true, value: protectedResourceMetadataResolver }); Object.defineProperty(this, "authorizationServerMetadataResolver", { enumerable: true, configurable: true, writable: true, value: authorizationServerMetadataResolver }); } /** * @param input - A handle, DID, PDS URL or Entryway URL */ async resolve(input, options) { // Allow using an entryway, or PDS url, directly as login input (e.g. // when the user forgot their handle, or when the handle does not // resolve to a DID) return /^https?:\/\//.test(input) ? this.resolveFromService(input, options) : this.resolveFromIdentity(input, options); } /** * @note this method can be used to verify if a particular uri supports OAuth * based sign-in (for compatibility with legacy implementation). */ async resolveFromService(input, options) { try { // Assume first that input is a PDS URL (as required by ATPROTO) const metadata = await this.getResourceServerMetadata(input, options); return { metadata }; } catch (err) { if (!options?.signal?.aborted && err instanceof oauth_resolver_error_js_1.OAuthResolverError) { try { // Fallback to trying to fetch as an issuer (Entryway) const result = oauth_types_1.oauthIssuerIdentifierSchema.safeParse(input); if (result.success) { const metadata = await this.getAuthorizationServerMetadata(result.data, options); return { metadata }; } } catch { // Fallback failed, throw original error } } throw err; } } async resolveFromIdentity(input, options) { const identity = await this.resolveIdentity(input, options); options?.signal?.throwIfAborted(); const metadata = await this.getResourceServerMetadata(identity.pds, options); return { identity, metadata }; } async resolveIdentity(input, options) { try { return await this.identityResolver.resolve(input, options); } catch (cause) { throw oauth_resolver_error_js_1.OAuthResolverError.from(cause, `Failed to resolve identity: ${input}`); } } async getAuthorizationServerMetadata(issuer, options) { try { return await this.authorizationServerMetadataResolver.get(issuer, options); } catch (cause) { throw oauth_resolver_error_js_1.OAuthResolverError.from(cause, `Failed to resolve OAuth server metadata for issuer: ${issuer}`); } } async getResourceServerMetadata(pdsUrl, options) { try { const rsMetadata = await this.protectedResourceMetadataResolver.get(pdsUrl, options); // ATPROTO requires one, and only one, authorization server entry if (rsMetadata.authorization_servers?.length !== 1) { throw new oauth_resolver_error_js_1.OAuthResolverError(rsMetadata.authorization_servers?.length ? `Unable to determine authorization server for PDS: ${pdsUrl}` : `No authorization servers found for PDS: ${pdsUrl}`); } const issuer = rsMetadata.authorization_servers[0]; options?.signal?.throwIfAborted(); const asMetadata = await this.getAuthorizationServerMetadata(issuer, options); // https://datatracker.ietf.org/doc/html/draft-ietf-oauth-resource-metadata-05#section-4 if (asMetadata.protected_resources) { if (!asMetadata.protected_resources.includes(rsMetadata.resource)) { throw new oauth_resolver_error_js_1.OAuthResolverError(`PDS "${pdsUrl}" not protected by issuer "${issuer}"`); } } return asMetadata; } catch (cause) { throw oauth_resolver_error_js_1.OAuthResolverError.from(cause, `Failed to resolve OAuth server metadata for resource: ${pdsUrl}`); } } } exports.OAuthResolver = OAuthResolver; //# sourceMappingURL=oauth-resolver.js.map