Skip to content

Commit

Permalink
chore: SDK-38 AuthorizationServerMetadata support
Browse files Browse the repository at this point in the history
  • Loading branch information
sanderPostma committed Oct 22, 2024
1 parent 8a3c5f7 commit 30235e0
Show file tree
Hide file tree
Showing 9 changed files with 456 additions and 25 deletions.
12 changes: 12 additions & 0 deletions packages/client/lib/__tests__/SdJwt.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import nock from 'nock';

import { OpenID4VCIClientV1_0_13 } from '..';
import { createAccessTokenResponse, IssuerMetadataBuilderV1_13, VcIssuerBuilder } from '../../../issuer';
import { AuthorizationServerMetadataBuilder } from '../../../issuer/lib/builder/AuthorizationServerMetadataBuilder'

export const UNIT_TEST_TIMEOUT = 30000;

Expand All @@ -27,8 +28,19 @@ const issuerMetadata = new IssuerMetadataBuilderV1_13()
} as CredentialConfigurationSupportedV1_0_13)
.build();

const authorizationServerMetadata = new AuthorizationServerMetadataBuilder()
.withIssuer(issuerMetadata.issuer)
.withCredentialEndpoint(issuerMetadata.credential_endpoint)
.withTokenEndpoint(issuerMetadata.token_endpoint)
.withAuthorizationEndpoint('https://token-endpoint.example.com/authorize')
.withTokenEndpointAuthMethodsSupported(['none', 'client_secret_basic', 'client_secret_jwt', 'client_secret_post'])
.withResponseTypesSupported(['code', 'token', 'id_token'])
.withScopesSupported(['openid', 'abcdef'])
.build();

const vcIssuer = new VcIssuerBuilder()
.withIssuerMetadata(issuerMetadata)
.withAuthorizationMetadata(authorizationServerMetadata)
.withInMemoryCNonceState()
.withInMemoryCredentialOfferState()
.withInMemoryCredentialOfferURIState()
Expand Down
4 changes: 2 additions & 2 deletions packages/issuer-rest/lib/OID4VCIServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
getCredentialEndpoint,
getCredentialOfferEndpoint,
getIssueStatusEndpoint,
getMetadataEndpoint,
getMetadataEndpoints,
pushedAuthorizationEndpoint,
} from './oid4vci-api-functions'

Expand Down Expand Up @@ -116,7 +116,7 @@ export class OID4VCIServer<DIDDoc extends object> {
this._issuer = opts?.issuer ? opts.issuer : buildVCIFromEnvironment()

pushedAuthorizationEndpoint(this.router, this.issuer, this.authRequestsData)
getMetadataEndpoint(this.router, this.issuer)
getMetadataEndpoints(this.router, this.issuer)
if (opts?.endpointOpts?.createCredentialOfferOpts?.enabled !== false || process.env.CREDENTIAL_OFFER_ENDPOINT_EBALBED === 'true') {
createCredentialOfferEndpoint(this.router, this.issuer, opts?.endpointOpts?.createCredentialOfferOpts)
}
Expand Down
41 changes: 37 additions & 4 deletions packages/issuer-rest/lib/__tests__/ClientIssuerIT.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ import {
JWTPayload,
OpenId4VCIVersion,
PRE_AUTH_CODE_LITERAL,
PRE_AUTH_GRANT_LITERAL,
PRE_AUTH_GRANT_LITERAL
} from '@sphereon/oid4vci-common'
import { VcIssuer } from '@sphereon/oid4vci-issuer/dist/VcIssuer'
import { CredentialSupportedBuilderV1_13, VcIssuerBuilder } from '@sphereon/oid4vci-issuer/dist/builder'
import {
AuthorizationServerMetadataBuilder
} from '@sphereon/oid4vci-issuer/dist/builder/AuthorizationServerMetadataBuilder'
import { MemoryStates } from '@sphereon/oid4vci-issuer/dist/state-manager'
import { ExpressBuilder, ExpressSupport } from '@sphereon/ssi-express-support'
import { IProofPurpose, IProofType } from '@sphereon/ssi-types'
Expand Down Expand Up @@ -54,6 +57,16 @@ describe('VcIssuer', () => {
// const clientId = 'sphereon:wallet'
const preAuthorizedCode = 'test_code'


const authorizationServerMetadata = new AuthorizationServerMetadataBuilder()
.withIssuer(ISSUER_URL)
.withCredentialEndpoint('http://localhost:3456/test/credential-endpoin')
.withTokenEndpoint('http://localhost:3456/test/token')
.withAuthorizationEndpoint('https://token-endpoint.example.com/authorize')
.withTokenEndpointAuthMethodsSupported(['none', 'client_secret_basic', 'client_secret_jwt', 'client_secret_post'])
.withResponseTypesSupported(['code', 'token', 'id_token'])
.withScopesSupported(['openid', 'abcdef'])
.build();
/*const preAuthorizedCode1 = 'SplxlOBeZQQYbYS6WxSbIA1'
const preAuthorizedCode2 = 'SplxlOBeZQQYbYS6WxSbIA2'
const preAuthorizedCode3 = 'SplxlOBeZQQYbYS6WxSbIA3'
Expand Down Expand Up @@ -105,7 +118,7 @@ describe('VcIssuer', () => {
}

vcIssuer = new VcIssuerBuilder<DIDDocument>()
// .withAuthorizationServer('https://authorization-server')
.withAuthorizationMetadata(authorizationServerMetadata)
.withCredentialEndpoint('http://localhost:3456/test/credential-endpoint')
.withDefaultCredentialOfferBaseUri('http://localhost:3456/test')
.withCredentialIssuer(ISSUER_URL)
Expand Down Expand Up @@ -255,9 +268,29 @@ describe('VcIssuer', () => {

it('should retrieve server metadata', async () => {
await expect(client.retrieveServerMetadata()).resolves.toEqual({
authorizationServerMetadata: undefined,
authorizationServerMetadata: {
'authorization_endpoint': 'https://token-endpoint.example.com/authorize',
'credential_endpoint': 'http://localhost:3456/test/credential-endpoin',
'issuer': 'http://localhost:3456/test',
'response_types_supported': [
'code',
'token',
'id_token'
],
'scopes_supported': [
'openid',
'abcdef'
],
'token_endpoint': 'http://localhost:3456/test/token',
'token_endpoint_auth_methods_supported': [
'none',
'client_secret_basic',
'client_secret_jwt',
'client_secret_post'
]
},
authorizationServerType: 'OID4VCI',
authorization_endpoint: undefined,
authorization_endpoint: 'https://token-endpoint.example.com/authorize',
deferred_credential_endpoint: undefined,
authorization_server: 'http://localhost:3456/test',
credentialIssuerMetadata: {
Expand Down
17 changes: 12 additions & 5 deletions packages/issuer-rest/lib/oid4vci-api-functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
trimEnd,
trimStart,
validateJWT,
WellKnownEndpoints
} from '@sphereon/oid4vci-common'
import { ITokenEndpointOpts, LOG, VcIssuer } from '@sphereon/oid4vci-issuer'
import { env, ISingleEndpointOpts, sendErrorResponse } from '@sphereon/ssi-express-support'
Expand All @@ -32,10 +33,11 @@ import {
ICreateCredentialOfferEndpointOpts,
ICreateCredentialOfferURIResponse,
IGetCredentialOfferEndpointOpts,
IGetIssueStatusEndpointOpts,
IGetIssueStatusEndpointOpts
} from './OID4VCIServer'
import { validateRequestBody } from './expressUtils'


const expiresIn = process.env.EXPIRES_IN ? parseInt(process.env.EXPIRES_IN) : 90

export function getIssueStatusEndpoint<DIDDoc extends object>(router: Router, issuer: VcIssuer<DIDDoc>, opts: IGetIssueStatusEndpointOpts) {
Expand Down Expand Up @@ -392,11 +394,16 @@ export function pushedAuthorizationEndpoint<DIDDoc extends object>(
})
}

export function getMetadataEndpoint<DIDDoc extends object>(router: Router, issuer: VcIssuer<DIDDoc>) {
const path = `/.well-known/openid-credential-issuer`
router.get(path, (request: Request, response: Response) => {
export function getMetadataEndpoints<DIDDoc extends object>(router: Router, issuer: VcIssuer<DIDDoc>) {
const credentialIssuerHandler = (request: Request, response: Response) => {
return response.send(issuer.issuerMetadata)
})
}
router.get(WellKnownEndpoints.OPENID4VCI_ISSUER, credentialIssuerHandler)

const authorizationServerHandler = (request: Request, response: Response) => {
return response.send(issuer.authorizationServerMetadata)
}
router.get(WellKnownEndpoints.OAUTH_AS, authorizationServerHandler)
}

export function determinePath(
Expand Down
13 changes: 11 additions & 2 deletions packages/issuer/lib/VcIssuer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { uuidv4 } from '@sphereon/oid4vc-common'
import {
ALG_ERROR,
AUD_ERROR,
AUD_ERROR, AuthorizationServerMetadata,
CNonceState,
CreateCredentialOfferURIResult,
CREDENTIAL_MISSING_ERROR,
Expand Down Expand Up @@ -36,7 +36,7 @@ import {
toUniformCredentialOfferRequest,
TxCode,
TYP_ERROR,
URIState,
URIState
} from '@sphereon/oid4vci-common'
import { CredentialEventNames, CredentialOfferEventNames, EVENTS } from '@sphereon/oid4vci-common'
import { CredentialIssuerMetadataOptsV1_0_13 } from '@sphereon/oid4vci-common'
Expand All @@ -48,6 +48,7 @@ import { CredentialDataSupplier, CredentialDataSupplierArgs, CredentialIssuanceI

export class VcIssuer<DIDDoc extends object> {
private readonly _issuerMetadata: CredentialIssuerMetadataOptsV1_0_13
private readonly _authorizationServerMetadata: AuthorizationServerMetadata
private readonly _defaultCredentialOfferBaseUri?: string
private readonly _credentialSignerCallback?: CredentialSignerCallback<DIDDoc>
private readonly _jwtVerifyCallback?: JWTVerifyCallback<DIDDoc>
Expand All @@ -59,6 +60,7 @@ export class VcIssuer<DIDDoc extends object> {

constructor(
issuerMetadata: CredentialIssuerMetadataOptsV1_0_13,
authorizationServerMetadata: AuthorizationServerMetadata,
args: {
txCode?: TxCode
baseUri?: string
Expand All @@ -74,6 +76,7 @@ export class VcIssuer<DIDDoc extends object> {
) {
this.setDefaultTokenEndpoint(issuerMetadata)
this._issuerMetadata = issuerMetadata
this._authorizationServerMetadata = authorizationServerMetadata
this._defaultCredentialOfferBaseUri = args.defaultCredentialOfferBaseUri
this._credentialOfferSessions = args.credentialOfferSessions
this._cNonces = args.cNonces
Expand Down Expand Up @@ -680,4 +683,10 @@ export class VcIssuer<DIDDoc extends object> {
public get issuerMetadata() {
return this._issuerMetadata
}

public get authorizationServerMetadata() {
return this._authorizationServerMetadata
}


}
Loading

0 comments on commit 30235e0

Please sign in to comment.