@atproto/oauth-client
Version:
OAuth client for ATPROTO PDS. This package serves as common base for environment-specific implementations (NodeJS, Browser, React-Native).
66 lines • 3.29 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.OAuthProtectedResourceMetadataResolver = void 0;
const fetch_1 = require("@atproto-labs/fetch");
const simple_store_1 = require("@atproto-labs/simple-store");
const oauth_types_1 = require("@atproto/oauth-types");
const util_js_1 = require("./util.js");
/**
* @see {@link https://datatracker.ietf.org/doc/html/draft-ietf-oauth-resource-metadata-05}
*/
class OAuthProtectedResourceMetadataResolver extends simple_store_1.CachedGetter {
constructor(cache, fetch = globalThis.fetch, config) {
super(async (origin, options) => this.fetchMetadata(origin, options), cache);
Object.defineProperty(this, "fetch", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
Object.defineProperty(this, "allowHttpResource", {
enumerable: true,
configurable: true,
writable: true,
value: void 0
});
this.fetch = (0, fetch_1.bindFetch)(fetch);
this.allowHttpResource = config?.allowHttpResource === true;
}
async get(resource, options) {
const { protocol, origin } = new URL(resource);
if (protocol !== 'https:' && protocol !== 'http:') {
throw new TypeError(`Invalid protected resource metadata URL protocol: ${protocol}`);
}
if (protocol === 'http:' && !this.allowHttpResource) {
throw new TypeError(`Unsecure resource metadata URL (${protocol}) only allowed in development and test environments`);
}
return super.get(origin, options);
}
async fetchMetadata(origin, options) {
const url = new URL(`/.well-known/oauth-protected-resource`, origin);
const request = new Request(url, {
signal: options?.signal,
headers: { accept: 'application/json' },
cache: options?.noCache ? 'no-cache' : undefined,
redirect: 'manual', // response must be 200 OK
});
const response = await this.fetch(request);
// https://datatracker.ietf.org/doc/html/draft-ietf-oauth-resource-metadata-05#section-3.2
if (response.status !== 200) {
await (0, fetch_1.cancelBody)(response, 'log');
throw await fetch_1.FetchResponseError.from(response, `Unexpected status code ${response.status} for "${url}"`, undefined, { cause: request });
}
if ((0, util_js_1.contentMime)(response.headers) !== 'application/json') {
await (0, fetch_1.cancelBody)(response, 'log');
throw await fetch_1.FetchResponseError.from(response, `Unexpected content type for "${url}"`, undefined, { cause: request });
}
const metadata = oauth_types_1.oauthProtectedResourceMetadataSchema.parse(await response.json());
// https://datatracker.ietf.org/doc/html/draft-ietf-oauth-resource-metadata-05#section-3.3
if (metadata.resource !== origin) {
throw new TypeError(`Invalid issuer ${metadata.resource}`);
}
return metadata;
}
}
exports.OAuthProtectedResourceMetadataResolver = OAuthProtectedResourceMetadataResolver;
//# sourceMappingURL=oauth-protected-resource-metadata-resolver.js.map