Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: auth code flow #2056

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions demo-openid/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,19 @@
"license": "Apache-2.0",
"scripts": {
"issuer": "ts-node src/IssuerInquirer.ts",
"provider": "tsx src/Provider.ts",
"holder": "ts-node src/HolderInquirer.ts",
"verifier": "ts-node src/VerifierInquirer.ts"
},
"dependencies": {
"@hyperledger/anoncreds-nodejs": "^0.2.2",
"@hyperledger/aries-askar-nodejs": "^0.2.3",
"@hyperledger/indy-vdr-nodejs": "^0.2.2",
"@koa/bodyparser": "^5.1.1",
"express": "^4.18.1",
"inquirer": "^8.2.5"
"inquirer": "^8.2.5",
"jose": "^5.3.0",
"oidc-provider": "^8.4.6"
},
"devDependencies": {
"@credo-ts/openid4vc": "workspace:*",
Expand All @@ -28,8 +32,10 @@
"@types/express": "^4.17.13",
"@types/figlet": "^1.5.4",
"@types/inquirer": "^8.2.6",
"@types/oidc-provider": "^8.4.4",
"clear": "^0.1.0",
"figlet": "^1.5.2",
"ts-node": "^10.4.0"
"ts-node": "^10.4.0",
"tsx": "^4.11.0"
}
}
24 changes: 21 additions & 3 deletions demo-openid/src/Holder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,34 @@ export class Holder extends BaseAgent<ReturnType<typeof getOpenIdHolderModules>>
resolvedCredentialOffer: OpenId4VciResolvedCredentialOffer,
credentialsToRequest: string[]
) {
const tokenResponse = await this.agent.modules.openId4VcHolder.requestToken({ resolvedCredentialOffer })
const resolvedAuthorizationRequest = await this.agent.modules.openId4VcHolder.resolveIssuanceAuthorizationRequest(
resolvedCredentialOffer,
{
clientId: 'foo',
redirectUri: 'http://example.com',
scope: ['openid', 'UniversityDegree'],
}
)

console.log(resolvedAuthorizationRequest.authorizationRequestUri)

let code = 'not a valid code!'
code = 'MU_MtTZjjhjmzuzGZdsLSam2GcC-7c4g_k5ukV2XO3i'

const tokenResponse = await this.agent.modules.openId4VcHolder.requestToken({
resolvedAuthorizationRequest,
code,
resolvedCredentialOffer,
})

const credentialResponse = await this.agent.modules.openId4VcHolder.requestCredentials({
resolvedCredentialOffer,
...tokenResponse,
// TODO: add jwk support for holder binding
credentialsToRequest,
credentialBindingResolver: async () => ({
method: 'did',
didUrl: this.verificationMethod.id,
}),
...tokenResponse,
})

const storedCredentials = await Promise.all(
Expand Down
11 changes: 8 additions & 3 deletions demo-openid/src/Issuer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
OpenId4VcCredentialHolderDidBinding,
OpenId4VciCredentialRequestToCredentialMapper,
OpenId4VciCredentialSupportedWithId,
OpenId4VciCredentialSupportedWithIdAndScope,
OpenId4VcIssuerRecord,
} from '@credo-ts/openid4vc'

Expand All @@ -28,13 +29,15 @@ export const universityDegreeCredential = {
id: 'UniversityDegreeCredential',
format: OpenId4VciCredentialFormatProfile.JwtVcJson,
types: ['VerifiableCredential', 'UniversityDegreeCredential'],
} satisfies OpenId4VciCredentialSupportedWithId
scope: 'openid4vc:credential:UniversityDegreeCredential',
} satisfies OpenId4VciCredentialSupportedWithIdAndScope

export const openBadgeCredential = {
id: 'OpenBadgeCredential',
format: OpenId4VciCredentialFormatProfile.JwtVcJson,
types: ['VerifiableCredential', 'OpenBadgeCredential'],
} satisfies OpenId4VciCredentialSupportedWithId
scope: 'openid4vc:credential:OpenBadgeCredential',
} satisfies OpenId4VciCredentialSupportedWithIdAndScope

export const universityDegreeCredentialSdJwt = {
id: 'UniversityDegreeCredential-sdjwt',
Expand Down Expand Up @@ -148,7 +151,9 @@ export class Issuer extends BaseAgent<{
const issuer = new Issuer(2000, 'OpenId4VcIssuer ' + Math.random().toString())
await issuer.initializeAgent('96213c3d7fc8d4d6754c7a0fd969598f')
issuer.issuerRecord = await issuer.agent.modules.openId4VcIssuer.createIssuer({
issuerId: '726222ad-7624-4f12-b15b-e08aa7042ffa',
credentialsSupported,
authorizationServerConfigs: [{ baseUrl: 'http://localhost:3042' }],
})

return issuer
Expand All @@ -158,7 +163,7 @@ export class Issuer extends BaseAgent<{
const { credentialOffer } = await this.agent.modules.openId4VcIssuer.createCredentialOffer({
issuerId: this.issuerRecord.issuerId,
offeredCredentials,
preAuthorizedCodeFlowConfig: { userPinRequired: false },
authorizationCodeFlowConfig: { issuerState: 'f498b73c-144f-4eea-bd6b-7be89b35936e' },
})

return credentialOffer
Expand Down
81 changes: 81 additions & 0 deletions demo-openid/src/Provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { bodyParser } from '@koa/bodyparser'
import Provider from 'oidc-provider'

Check warning on line 2 in demo-openid/src/Provider.ts

View workflow job for this annotation

GitHub Actions / Validate

Using exported name 'Provider' as identifier for default export

const oidc = new Provider('http://localhost:3042', {
clients: [
{
client_id: 'foo',
client_secret: 'bar',
redirect_uris: ['http://example.com'],
scope: 'openid',
grant_types: ['authorization_code'],
},
],
pkce: {
methods: ['S256'],
required: () => {
console.log('checking pkce')
return true
},
},
features: {
dPoP: { enabled: false },
pushedAuthorizationRequests: {
enabled: true,
//requirePushedAuthorizationRequests: true,
},
},

async findAccount(ctx, id) {
console.log('called findAccount')
return {
accountId: id,
async claims(use, scope) {
console.log('called claims', scope)
return { sub: id }
},
}
},
})

oidc.use(bodyParser())
oidc.use(async (ctx, next) => {
/** pre-processing
* you may target a specific action here by matching `ctx.path`
*/

console.log('pre middleware', ctx.method, ctx.path)

if (ctx.path.includes('request')) {
console.log(ctx.request.body)
ctx.request.body.client_secret = 'bar'
}

if (ctx.path.includes('auth')) {
const match = ctx.body?.match(/code=([^&]*)/)
const code = match ? match[1] : null
console.log('code', code)
}

if (ctx.path.includes('token')) {
console.log('token endpoint')
ctx.request.body.client_secret = 'bar'
}

await next()

/** post-processing
* since internal route matching was already executed you may target a specific action here
* checking `ctx.oidc.route`, the unique route names used are
*/

console.log('post middleware', ctx.method, ctx.oidc?.route)
if (ctx.path.includes('token')) {
console.log('token endpoint')
ctx.response.body
}
})

oidc.listen(3042, () => {
console.log('oidc-provider listening on port 3042, check http://localhost:3042/.well-known/openid-configuration')
})
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ export class OpenId4VciHolderService {
const codeVerifier = (
await Promise.all([agentContext.wallet.generateNonce(), agentContext.wallet.generateNonce()])
).join('')

const codeVerifierSha256 = Hasher.hash(codeVerifier, 'sha-256')
const codeChallenge = TypedArrayEncoder.toBase64URL(codeVerifierSha256)

Expand All @@ -202,9 +203,6 @@ export class OpenId4VciHolderService {
})

const authDetailsLocation = metadata.credentialIssuerMetadata.authorization_server
? metadata.credentialIssuerMetadata.authorization_server
: undefined

const authDetails = offeredCredentials
.map((credential) => this.getAuthDetailsFromOfferedCredential(credential, authDetailsLocation))
.filter((authDetail): authDetail is AuthorizationDetails => authDetail !== undefined)
Expand Down Expand Up @@ -237,6 +235,7 @@ export class OpenId4VciHolderService {
scope: scope ? scope.join(' ') : undefined,
authorizationDetails: authDetails,
parMode: PARMode.AUTO,
clientId,
},
})

Expand Down Expand Up @@ -342,6 +341,9 @@ export class OpenId4VciHolderService {
codeVerifier,
redirectUri,
createDPoPOpts,
additionalParams: {
client_id: resolvedAuthorizationRequest.clientId,
},
})
} else {
accessTokenResponse = await accessTokenClient.acquireAccessToken({
Expand Down
Loading
Loading