UNPKG

@microsoft/useragent-sdk

Version:

SDK for building decentralized identity wallets and enterprise agents.

191 lines (161 loc) 5.95 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import Identifier from '../Identifier'; import UserAgentError from '../UserAgentError'; import ClaimObject from '../credentials/ClaimObject'; import OidcResponse from './OidcResponse'; import OIDCAuthenticationRequest from '../crypto/protocols/did/requests/OIDCAuthenticationRequest'; import CryptoOptions from '../CryptoOptions'; import CryptoFactory from '../crypto/plugin/CryptoFactory'; import JwsToken from '../crypto/protocols/jose/jws/JwsToken'; import UserAgentOptions from '../UserAgentOptions'; import HttpResolver from '../resolvers/HttpResolver'; import VerifyHelper from './VerifyHelper'; /** * Optional Parameters to add to OIDCRequests. */ export type OptionalOIDCRequestParams = { /** * Opaque value to represent state on serverside. */ state?: string; /** * ClaimObject if OIDC Request involves issuance of credential. */ claimObject?: ClaimObject; /** * Claim Requests if requesting to be presented with credential. */ claimsRequested?: string[]; }; /** * Standard response type for SIOP. */ const responseType = 'id_token' /** * Standard response mode for SIOP. */ const responseMode = 'form_post' /** * Standard scope for SIOP. */ const scope = 'openid did_authn' /** * Class to represent Open ID Connect Self-Issued Tokens * @class */ export default class OidcRequest { /** * Redirect URL for SIOP. */ public redirectUrl: string; /** * Nonce for SIOP. */ public nonce: string; /** * Sender of the request. */ public sender: Identifier; /** * Optional claimObject attached to OIDC request. */ public claimObject?: ClaimObject; /** * Opaque value to represent state on serverside. */ public state?: string; /** * Optional Claim that is requested for presentation. */ public claimsRequested?: string[]; /** * Instantiates an self-signed OIDC Request. * @param sender Identifier who will sign request. * @param redirectUrl Redirect URL for SIOP. * @param nonce Nonce for SIOP. * @param claimObject optional claimObject to attach to request. */ constructor(sender: Identifier, redirectUrl: string, nonce: string, options?: OptionalOIDCRequestParams) { this.sender = sender; this.redirectUrl = redirectUrl; this.nonce = nonce; this.claimObject = options!.claimObject; this.state = options!.state; this.claimsRequested = options!.claimsRequested; } /** * Forms the request to spec and sign the request. * @param keyReference * @returns jwt in compact form. */ public async sign(keyReference: string): Promise<string> { const request: Partial<OIDCAuthenticationRequest> = { iss: this.sender.id, response_type: responseType, response_mode: responseMode, client_id: this.redirectUrl, scope, nonce: this.nonce } if (this.state) { Object.assign(request, {state: this.state}); } if (this.claimsRequested) { const claimsRequestIdToken: {[key: string]: any} = {}; // Assuming every claim requested is essential for now. this.claimsRequested.forEach(claimRef => { claimsRequestIdToken[claimRef] = { essential: true } }); Object.assign(request, {claims: {id_token: claimsRequestIdToken}}); } if (this.claimObject) { Object.assign(request, {offer: JSON.parse(this.claimObject.serialize())}); } return this.sender.sign(request, keyReference); } /** * Parses and Verifies signed JWT. * @param signedRequest signed JWT containing OIDC request. * @returns OidcRequest Object if verified. */ public static async verifyAndParse(signedRequest: string, cryptoFactory?: CryptoFactory): Promise<OidcRequest> { if (!cryptoFactory) { cryptoFactory = new CryptoOptions().cryptoFactory; } // get identifier id from key id in header. const token : JwsToken = await JwsToken.deserialize(signedRequest, {cryptoFactory}); const request = JSON.parse(token.payload.toString()); const senderId = request.iss; const options = new UserAgentOptions(); options.resolver = new HttpResolver('https://beta.discover.did.microsoft.com'); const sender = new Identifier(senderId, options) // if (!await VerifyHelper.verify(sender, token)) { console.log('not verifying for now'); // throw new UserAgentError(`Invalid signature for token issued by: ${request.iss}`); // } const requestOptions: OptionalOIDCRequestParams = { state: request.state, claimObject: request.offer, }; // parse out requested claims to list if param is present. if (request.claims && request.claims.id_token) { const claimsRequested = Object.keys(request.claims.id_token); Object.assign(requestOptions, {claimsRequested}); } return new OidcRequest(sender, request.client_id, request.nonce, requestOptions); } /** * Respond to OIDC Request using identifier on the client side. * @param identifier the identifier used to sign response * @returns the body of the HTTP response if receive status 200. */ public async respondWith(identifier: Identifier, keyReference: string, claimObjects?: ClaimObject[]): Promise<string> { const oidcResponse = await OidcResponse.create(this, identifier); return oidcResponse.signAndSend(keyReference, claimObjects); } }