@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 • 2.92 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateClientMetadata = validateClientMetadata;
const oauth_types_1 = require("@atproto/oauth-types");
const types_js_1 = require("./types.js");
const TOKEN_ENDPOINT_AUTH_METHOD = `token_endpoint_auth_method`;
const TOKEN_ENDPOINT_AUTH_SIGNING_ALG = `token_endpoint_auth_signing_alg`;
function validateClientMetadata(input, keyset) {
if (input.jwks) {
if (!keyset) {
throw new TypeError(`Keyset must not be provided when jwks is provided`);
}
for (const key of input.jwks.keys) {
if (!key.kid) {
throw new TypeError(`Key must have a "kid" property`);
}
else if (!keyset.has(key.kid)) {
throw new TypeError(`Key with kid "${key.kid}" not found in keyset`);
}
}
}
// Allow to pass a keyset and omit the jwks/jwks_uri properties
if (!input.jwks && !input.jwks_uri && keyset?.size) {
input = { ...input, jwks: keyset.toJSON() };
}
const metadata = types_js_1.clientMetadataSchema.parse(input);
// Validate client ID
if (metadata.client_id.startsWith('http:')) {
(0, oauth_types_1.assertOAuthLoopbackClientId)(metadata.client_id);
}
else {
(0, oauth_types_1.assertOAuthDiscoverableClientId)(metadata.client_id);
}
const scopes = metadata.scope?.split(' ');
if (!scopes?.includes('atproto')) {
throw new TypeError(`Client metadata must include the "atproto" scope`);
}
if (!metadata.response_types.includes('code')) {
throw new TypeError(`"response_types" must include "code"`);
}
if (!metadata.grant_types.includes('authorization_code')) {
throw new TypeError(`"grant_types" must include "authorization_code"`);
}
const method = metadata[TOKEN_ENDPOINT_AUTH_METHOD];
switch (method) {
case undefined:
throw new TypeError(`${TOKEN_ENDPOINT_AUTH_METHOD} must be provided`);
case 'none':
if (metadata[TOKEN_ENDPOINT_AUTH_SIGNING_ALG]) {
throw new TypeError(`${TOKEN_ENDPOINT_AUTH_SIGNING_ALG} must not be provided when ${TOKEN_ENDPOINT_AUTH_METHOD} is "${method}"`);
}
break;
case 'private_key_jwt':
if (!keyset?.size) {
throw new TypeError(`A non-empty keyset must be provided when ${TOKEN_ENDPOINT_AUTH_METHOD} is "${method}"`);
}
if (!metadata[TOKEN_ENDPOINT_AUTH_SIGNING_ALG]) {
throw new TypeError(`${TOKEN_ENDPOINT_AUTH_SIGNING_ALG} must be provided when ${TOKEN_ENDPOINT_AUTH_METHOD} is "${method}"`);
}
break;
default:
throw new TypeError(`Invalid "token_endpoint_auth_method" value: ${method}`);
}
return metadata;
}
//# sourceMappingURL=validate-client-metadata.js.map