Skip to content

Commit

Permalink
Fetch authorization server meta data.
Browse files Browse the repository at this point in the history
  • Loading branch information
dlongley committed Aug 10, 2023
1 parent c4b3787 commit 4579fab
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 17 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# @digitalbazaar/oid4-client Changelog

## 3.0.1 - 2023-08-dd

### Fixed
- Ensure authorization server metadata is retrieved along with credential
issuer metadata. This information is combined to create the `issuerConfig`
stored in the client. The client also stores `metadata` with the original
metadata from each to allow differentiation as needed. A future version may
remove `issuerConfig` to avoid any conflation that was the result of previous
versions of the OID4VCI spec and implementations built off of this client.

## 3.0.0 - 2023-08-09

### Changed
Expand Down
9 changes: 6 additions & 3 deletions lib/OID4Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ const GRANT_TYPES = new Map([
const HEADERS = {accept: 'application/json'};

export class OID4Client {
constructor({accessToken = null, agent, issuerConfig, offer} = {}) {
constructor({accessToken = null, agent, issuerConfig, metadata, offer} = {}) {
this.accessToken = accessToken;
this.agent = agent;
this.metadata = metadata;
this.issuerConfig = issuerConfig;
this.offer = offer;
}
Expand Down Expand Up @@ -234,7 +235,8 @@ export class OID4Client {
const issuerConfigUrl =
`${parsedIssuer.origin}/.well-known/openid-credential-issuer` +
parsedIssuer.pathname;
const issuerConfig = await discoverIssuer({issuerConfigUrl, agent});
const {issuerConfig, metadata} = await discoverIssuer(
{issuerConfigUrl, agent});

/* First get access token from AS (Authorization Server), e.g.:
Expand Down Expand Up @@ -298,7 +300,8 @@ export class OID4Client {
}

// create client w/access token
return new OID4Client({accessToken, agent, issuerConfig, offer});
return new OID4Client(
{accessToken, agent, issuerConfig, metadata, offer});
} catch(cause) {
const error = new Error('Could not create OID4 client.');
error.name = 'OperationError';
Expand Down
54 changes: 40 additions & 14 deletions lib/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,24 +14,20 @@ export async function discoverIssuer({issuerConfigUrl, agent} = {}) {
throw new TypeError('"issuerConfigUrl" must be a string.');
}

// allow these params to be passed / configured
const fetchOptions = {
// max size for issuer config related responses (in bytes, ~4 KiB)
size: 4096,
// timeout in ms for fetching an issuer config
timeout: 5000,
agent
};

const response = await httpClient.get(issuerConfigUrl, fetchOptions);
const response = await _fetchJSON({url: issuerConfigUrl, agent});
if(!response.data) {
const error = new Error('Issuer configuration format is not JSON.');
error.name = 'DataError';
throw error;
}

const {data: config} = response;
const {issuer, token_endpoint} = config;
const {data: issuerMetaData} = response;
const {issuer, authorization_server} = issuerMetaData;

if(authorization_server && authorization_server !== issuer) {
// not yet implemented
throw new Error('Separate authorization server not yet implemented.');
}

// validate `issuer`
if(!(typeof issuer === 'string' && issuer.startsWith('https://'))) {
Expand Down Expand Up @@ -63,16 +59,33 @@ export async function discoverIssuer({issuerConfigUrl, agent} = {}) {
throw error;
}

// fetch AS meta data
const asMetaDataUrl =
`${origin}/.well-known/oauth-authorization-server${pathname}`;
const asMetaDataResponse = await _fetchJSON({url: asMetaDataUrl, agent});
if(!asMetaDataResponse.data) {
const error = new Error('Authorization server meta data is not JSON.');
error.name = 'DataError';
throw error;
}

const {data: asMetaData} = response;
// merge AS meta data into total issuer config
const issuerConfig = {...issuerMetaData, ...asMetaData};

// ensure `token_endpoint` is valid
const {token_endpoint} = asMetaData;
if(!(token_endpoint && typeof token_endpoint === 'string')) {
const error = new TypeError('"token_endpoint" must be a string.');
error.name = 'DataError';
throw error;
}

return config;
// return merged config and separate issuer and AS configs
const metadata = {issuer: issuerMetaData, authorizationServer: asMetaData};
return {issuerConfig, metadata};
} catch(cause) {
const error = new Error('Could not get OAuth2 issuer configuration.');
const error = new Error('Could not get OpenID issuer configuration.');
error.name = 'OperationError';
error.cause = cause;
throw error;
Expand Down Expand Up @@ -181,3 +194,16 @@ function _curveToAlg(crv) {
}
return crv;
}

function _fetchJSON({url, agent}) {
// allow these params to be passed / configured
const fetchOptions = {
// max size for issuer config related responses (in bytes, ~4 KiB)
size: 4096,
// timeout in ms for fetching an issuer config
timeout: 5000,
agent
};

return httpClient.get(url, fetchOptions);
}

0 comments on commit 4579fab

Please sign in to comment.