Exemplo n.º 1
0
        private async Task <ApiResponseType> PostDomesticPayment <ApiRequestType, ApiResponseType>(
            ApiRequestType payment,
            ApiProfile apiProfile,
            SoftwareStatementProfile softwareStatementProfile,
            BankClientProfile bankClientProfile,
            TokenEndpointResponse tokenEndpointResponse)
            where ApiRequestType : class
            where ApiResponseType : class
        {
            string     payloadJson = JsonConvert.SerializeObject(payment);
            UriBuilder ub          = new UriBuilder(new Uri(apiProfile.BaseUrl + "/domestic-payments"));

            List <HttpHeader> headers = CreateRequestHeaders(
                softwareStatement: softwareStatementProfile,
                payment: payment,
                client: bankClientProfile,
                tokenEndpointResponse: tokenEndpointResponse);

            return(await new HttpRequestBuilder()
                   .SetMethod(HttpMethod.Post)
                   .SetUri(ub.Uri)
                   .SetHeaders(headers)
                   .SetContentType("application/json")
                   .SetContent(payloadJson)
                   .Create()
                   .RequestJsonAsync <ApiResponseType>(client: _apiClient, requestContentIsJson: true));
        }
        public async Task CreateAsync(AuthorisationCallbackDataPublic redirectData)
        {
            redirectData.ArgNotNull(nameof(redirectData));

            // Load relevant data objects
            DomesticConsent consent =
                (await _domesticConsentRepo.GetAsync(dc => dc.State == redirectData.Response.State))
                .FirstOrDefault() ?? throw new KeyNotFoundException(
                          $"Consent with redirect state '{redirectData.Response.State}' not found.");
            ApiProfile apiProfile = await _apiProfileRepo.GetAsync(consent.ApiProfileId) ??
                                    throw new KeyNotFoundException("API profile cannot be found.");

            BankClientProfile bankClientProfile =
                await _openBankingClientRepo.GetAsync(apiProfile.BankClientProfileId) ??
                throw new KeyNotFoundException("Bank client profile cannot be found.");

            SoftwareStatementProfile softwareStatementProfile =
                _softwareStatementProfileService.GetSoftwareStatementProfile(
                    bankClientProfile.SoftwareStatementProfileId);

            // Obtain token for consent
            string redirectUrl = softwareStatementProfile.DefaultFragmentRedirectUrl;
            TokenEndpointResponse tokenEndpointResponse =
                await PostAuthCodeGrant(
                    authCode : redirectData.Response.Code,
                    redirectUrl : redirectUrl,
                    client : bankClientProfile);

            // Update consent with token
            consent.TokenEndpointResponse = tokenEndpointResponse;
            await _dbContextService.SaveChangesAsync();
        }
Exemplo n.º 3
0
        public static OpenBankingClientRegistrationClaims CreateRegistrationClaims(
            string issuerUrl,
            SoftwareStatementProfile sProfile,
            bool concatScopes)
        {
            sProfile.ArgNotNull(nameof(sProfile));

            OpenBankingClientRegistrationClaims registrationClaims = new OpenBankingClientRegistrationClaims
            {
                Iss          = sProfile.SoftwareStatementPayload.SoftwareId,
                Aud          = issuerUrl,
                RedirectUris = sProfile.SoftwareStatementPayload.SoftwareRedirectUris,
                SoftwareId   = sProfile.SoftwareStatementPayload.SoftwareId,
                Scope        = sProfile.SoftwareStatementPayload.Scope,

                /*                Scope = concatScopes
                 *                  ? new[] { sProfile.SoftwareStatementPayload.Scope }
                 *                  : sProfile.SoftwareStatementPayload.Scope.Split(' ', StringSplitOptions.RemoveEmptyEntries),
                 */
                SoftwareStatement      = sProfile.SoftwareStatement,
                TlsClientAuthSubjectDn =
                    $"CN={sProfile.SoftwareStatementPayload.SoftwareId},OU={sProfile.SoftwareStatementPayload.OrgId},O=OpenBanking,C=GB"
            };

            return(registrationClaims);
        }
        public async Task Create_IdReturned()
        {
            IDbEntityRepository <SoftwareStatementProfile>?repo =
                Substitute.For <IDbEntityRepository <SoftwareStatementProfile> >();
            ISoftwareStatementProfileService?service   = Substitute.For <ISoftwareStatementProfileService>();
            IDbMultiEntityMethods?           dbMethods = Substitute.For <IDbMultiEntityMethods>();
            IEntityMapper?mapper = Substitute.For <IEntityMapper>();

            SoftwareStatementProfile?resultProfile = new SoftwareStatementProfile();

            mapper.Map <SoftwareStatementProfile>(Arg.Any <Models.Public.Request.SoftwareStatementProfile>())
            .Returns(resultProfile);

            CreateSoftwareStatementProfile?interaction =
                new CreateSoftwareStatementProfile(softwareStatementProfileService: service);

            Models.Public.Request.SoftwareStatementProfile?profile = new Models.Public.Request.SoftwareStatementProfile
            {
                DefaultFragmentRedirectUrl = "http://test.com",
                SigningKey           = "a",
                SigningKeyId         = "b",
                SigningCertificate   = "e30=",
                TransportKey         = "a",
                TransportCertificate = "a",
                SoftwareStatement    = "e30=.e30=.e30="
            };

            SoftwareStatementProfileResponse?result = await interaction.CreateAsync(profile);

            result.Should().NotBeNull();
        }
Exemplo n.º 5
0
        private static List <HttpHeader> CreateRequestHeaders <ApiRequestType>(
            SoftwareStatementProfile softwareStatement,
            ApiRequestType payment,
            BankClientProfile client,
            TokenEndpointResponse tokenEndpointResponse)
            where ApiRequestType : class
        {
            JwtFactory jwtFactory = new JwtFactory();
            string     jwt        = jwtFactory.CreateJwt(
                profile: softwareStatement,
                claims: payment,
                useOpenBankingJwtHeaders: true);

            string[]          jwsComponents = jwt.Split('.');
            string            jwsSig        = $"{jwsComponents[0]}..{jwsComponents[2]}";
            List <HttpHeader> headers       = new List <HttpHeader>
            {
                new HttpHeader(name: "x-fapi-financial-id", value: client.XFapiFinancialId),
                new HttpHeader(name: "Authorization", value: "Bearer " + tokenEndpointResponse.AccessToken),
                new HttpHeader(name: "x-idempotency-key", value: Guid.NewGuid().ToString()),
                new HttpHeader(name: "x-jws-signature", value: jwsSig)
            };

            return(headers);
        }
Exemplo n.º 6
0
        public void GlobalSetup()
        {
            _entityMapper = new EntityMapper();

            _dataInitiation    = CreateDataInitiation();
            _risk              = CreateRisk();
            _domesticConsent   = CreateDomesticConsent();
            _softwareStatement = CreateSoftwareStatement();
            _client            = CreateClient();
        }
Exemplo n.º 7
0
        public static SoftwareStatementProfileContext Data(
            this SoftwareStatementProfileContext context,
            SoftwareStatementProfile value)
        {
            context.ArgNotNull(nameof(context));
            value.ArgNotNull(nameof(value));

            context.Data = value;

            return(context);
        }
Exemplo n.º 8
0
        public static SoftwareStatementProfileContext TransportKeyInfo(
            this SoftwareStatementProfileContext context,
            string keySecretName,
            string certificate)
        {
            SoftwareStatementProfile data = context.ArgNotNull(nameof(context)).GetOrCreateDefault(DataLens);

            data.TransportKey         = keySecretName;
            data.TransportCertificate = certificate;

            return(context);
        }
Exemplo n.º 9
0
        public async Task SetSoftwareStatementProfileFromSecrets()
        {
            // Get active software statement profile
            IEnumerable <string> profiles =
                await _activeSoftwareStatementProfilesRepo.GetListAsync(
                    nameof(ActiveSoftwareStatementProfiles.ProfileIds));

            if (!profiles.Any())
            {
                throw new KeyNotFoundException("No active software statement profiles found.");
            }

            string defaultProfileId = profiles.ElementAt(0);

            SoftwareStatementProfile softwareStatementProfile =
                await _softwareStatementProfileRepo.GetAsync(defaultProfileId);

            SetSoftwareStatementProfile(softwareStatementProfile);
        }
Exemplo n.º 10
0
        public Property Validate_ObSigningPem(string value)
        {
            Func <bool> rule = () =>
            {
                var profile = new SoftwareStatementProfile
                {
                    DefaultFragmentRedirectUrl = "http://test.com",
                    SigningKey           = "a",
                    SigningKeyId         = "a",
                    SigningCertificate   = value,
                    TransportKey         = "a",
                    TransportCertificate = "a",
                    SoftwareStatement    = "a.b.c"
                };

                var results = new SoftwareStatementProfileValidator().Validate(profile).Errors.ToList();

                return(results.Count == 0);
            };

            return(rule.When(!string.IsNullOrWhiteSpace(value)));
        }
Exemplo n.º 11
0
        public Property Validate_DefaultFragmentRedirectUrl_InvalidString(string value)
        {
            Func <bool> rule = () =>
            {
                var profile = new SoftwareStatementProfile
                {
                    DefaultFragmentRedirectUrl = value,
                    SigningKey           = "a",
                    SigningKeyId         = "a",
                    SigningCertificate   = "a",
                    TransportKey         = "a",
                    TransportCertificate = "a",
                    SoftwareStatement    = "a.b.c"
                };

                var results = new SoftwareStatementProfileValidator().Validate(profile).Errors.ToList();

                return(results.Count == 1);
            };

            return(rule.ToProperty());
        }
Exemplo n.º 12
0
        public void SetSoftwareStatementProfile(SoftwareStatementProfile profile)
        {
            profile.ArgNotNull(nameof(profile));

            Models.Persistent.SoftwareStatementProfile value =
                _mapper.Map <Models.Persistent.SoftwareStatementProfile>(profile);

            value.State = "ok";

            string[] softwareStatementComponentsBase64 = profile.SoftwareStatement.Split(new[] { '.' });
            if (softwareStatementComponentsBase64.Length != 3)
            {
                throw new ArgumentException("softwareStatementComponentsBase64 needs 3 components.");
            }

            value.SoftwareStatementHeaderBase64  = softwareStatementComponentsBase64[0];
            value.SoftwareStatementPayloadBase64 = softwareStatementComponentsBase64[1];
            value.SoftwareStatementPayload       =
                value.SoftwareStatementPayloadFromBase64(softwareStatementComponentsBase64[1]);
            value.SoftwwareStatementSignatureBase64 = softwareStatementComponentsBase64[2];

            _defaultSoftwareStatementProfile = value;
        }
Exemplo n.º 13
0
        public string CreateJwt <TClaims>(
            SoftwareStatementProfile profile,
            TClaims claims,
            bool useOpenBankingJwtHeaders) where TClaims : class
        {
            profile.ArgNotNull(nameof(profile));
            claims.ArgNotNull(nameof(claims));

            Dictionary <string, object> headers = useOpenBankingJwtHeaders
                ? CreateOpenBankingJwtHeaders(
                signingId: profile.SigningKeyId,
                orgId: profile.SoftwareStatementPayload.OrgId,
                softwareId: profile.SoftwareStatementPayload.SoftwareId)
                : CreateJwtHeaders(profile.SigningKeyId);


            string payloadJson = JsonConvert.SerializeObject(
                value: claims,
                settings: new JsonSerializerSettings
            {
                NullValueHandling = NullValueHandling.Ignore
            });

            X509Certificate2 privateKey = CertificateFactories.GetCertificate2FromPem(
                privateKey: profile.SigningKey,
                pem: profile.SigningCertificate);
            RSA privateKeyRsa = privateKey.GetRSAPrivateKey();

            string result = JWT.Encode(
                payload: payloadJson,
                key: privateKeyRsa,
                algorithm: JwsAlgorithm.PS256,
                extraHeaders: headers);

            return(result);
        }
Exemplo n.º 14
0
        private async Task <ApiResponseType> PostDomesticConsent <ApiRequestType, ApiResponseType>(
            JwtFactory jwtFactory,
            SoftwareStatementProfile softwareStatementProfile,
            ApiRequestType consent,
            ApiProfile apiProfile,
            BankClientProfile bankClientProfile,
            TokenEndpointResponse tokenEndpointResponse)
            where ApiRequestType : class
            where ApiResponseType : class
        {
            string jwt = jwtFactory.CreateJwt(
                profile: softwareStatementProfile,
                claims: consent,
                useOpenBankingJwtHeaders: true);

            string[]          jwsComponents = jwt.Split('.');
            string            jwsSignature  = $"{jwsComponents[0]}..{jwsComponents[2]}";
            UriBuilder        ub            = new UriBuilder(new Uri(apiProfile.BaseUrl + "/domestic-payment-consents"));
            string            payloadJson   = JsonConvert.SerializeObject(consent);
            List <HttpHeader> headers       = new List <HttpHeader>
            {
                new HttpHeader(name: "x-fapi-financial-id", value: bankClientProfile.XFapiFinancialId),
                new HttpHeader(name: "Authorization", value: "Bearer " + tokenEndpointResponse.AccessToken),
                new HttpHeader(name: "x-idempotency-key", value: Guid.NewGuid().ToString()),
                new HttpHeader(name: "x-jws-signature", value: jwsSignature)
            };

            return(await new HttpRequestBuilder()
                   .SetMethod(HttpMethod.Post)
                   .SetUri(ub.Uri)
                   .SetHeaders(headers)
                   .SetContentType("application/json")
                   .SetContent(payloadJson)
                   .Create()
                   .RequestJsonAsync <ApiResponseType>(client: _apiClient, requestContentIsJson: true));
        }
 public SoftwareStatementProfileContext(ISharedContext context)
 {
     Context = context.ArgNotNull(nameof(context));
     Data    = new SoftwareStatementProfile();
 }
        public async Task <BankClientProfileResponse> CreateAsync(BankClientProfilePublic bankClientProfile)
        {
            bankClientProfile.ArgNotNull(nameof(bankClientProfile));

            // Load relevant objects
            SoftwareStatementProfile softwareStatementProfile =
                _softwareStatementProfileService.GetSoftwareStatementProfile(
                    bankClientProfile.SoftwareStatementProfileId);

            // STEP 1
            // Compute claims associated with Open Banking client

            // Get OpenID Connect configuration info
            OpenIdConfiguration openIdConfiguration =
                await GetOpenIdConfigurationAsync(bankClientProfile.IssuerUrl);

            new OpenBankingOpenIdConfigurationResponseValidator().Validate(openIdConfiguration)
            .RaiseErrorOnValidationError();

            // Create claims for client reg
            OpenBankingClientRegistrationClaims registrationClaims = Factories.CreateRegistrationClaims(
                issuerUrl: bankClientProfile.IssuerUrl,
                sProfile: softwareStatementProfile,
                concatScopes: false);
            BankClientRegistrationClaimsOverrides registrationClaimsOverrides =
                bankClientProfile.BankClientRegistrationClaimsOverrides;

            if (!(registrationClaimsOverrides is null))
            {
                if (!(registrationClaimsOverrides.RequestAudience is null))
                {
                    registrationClaims.Aud = registrationClaimsOverrides.RequestAudience;
                }
            }

            BankClientRegistrationClaims persistentRegistrationClaims =
                _mapper.Map <BankClientRegistrationClaims>(registrationClaims);

            // STEP 2
            // Check for existing Open Banking client for issuer URL
            // If we have an Open Banking client with the same issuer URL we will check if the claims match.
            // If they do, we will re-use this client.
            // Otherwise we will return an error as only support a single client per issuer URL at present.
            IQueryable <BankClientProfile> clientList = await _bankClientProfileRepo
                                                        .GetAsync(c => c.IssuerUrl == bankClientProfile.IssuerUrl);

            BankClientProfile existingClient = clientList
                                               .SingleOrDefault();

            if (existingClient is object)
            {
                if (existingClient.BankClientRegistrationClaims != persistentRegistrationClaims)
                {
                    throw new Exception(
                              "There is already a client for this issuer URL but it cannot be re-used because claims are different.");
                }
            }

            // STEP 3
            // Create new Open Banking client by posting JWT
            BankClientProfile client;

            if (existingClient is null)
            {
                JwtFactory jwtFactory = new JwtFactory();
                string     jwt        = jwtFactory.CreateJwt(
                    profile: softwareStatementProfile,
                    claims: registrationClaims,
                    useOpenBankingJwtHeaders: false);

                OpenBankingClientRegistrationResponse registrationResponse = await new HttpRequestBuilder()
                                                                             .SetMethod(HttpMethod.Post)
                                                                             .SetUri(openIdConfiguration.RegistrationEndpoint)
                                                                             .SetContent(jwt)
                                                                             .SetContentType("application/jwt")
                                                                             .Create()
                                                                             .RequestJsonAsync <OpenBankingClientRegistrationResponse>(
                    client: _apiClient,
                    requestContentIsJson: false);

                BankClientRegistrationData openBankingClientResponse = new BankClientRegistrationData
                {
                    ClientId              = registrationResponse.ClientId,
                    ClientIdIssuedAt      = registrationResponse.ClientIdIssuedAt,
                    ClientSecret          = registrationResponse.ClientSecret,
                    ClientSecretExpiresAt = registrationResponse.ClientSecretExpiresAt
                };

                // Create and store Open Banking client
                BankClientProfile newClient = _mapper.Map <BankClientProfile>(bankClientProfile);
                client = await PersistOpenBankingClient(
                    value : newClient,
                    openIdConfiguration : openIdConfiguration,
                    registrationClaims : registrationClaims,
                    openBankingRegistrationData : openBankingClientResponse);

                await _dbMultiEntityMethods.SaveChangesAsync();
            }
            else
            {
                client = existingClient;
            }

            // Return
            return(new BankClientProfileResponse(client));
        }
Exemplo n.º 17
0
        public async Task <OBWriteDomesticResponse4> CreateAsync(string consentId)
        {
            // Load relevant data objects
            DomesticConsent consent = await _domesticConsentRepo.GetAsync(consentId)
                                      ?? throw new KeyNotFoundException("The Consent does not exist.");

            ApiProfile apiProfile = await _apiProfileRepo.GetAsync(consent.ApiProfileId)
                                    ?? throw new KeyNotFoundException("The API Profile does not exist.");

            BankClientProfile bankClientProfile = await _openBankingClientRepo.GetAsync(apiProfile.BankClientProfileId)
                                                  ?? throw new KeyNotFoundException(
                                                            "The Bank Client Profile does not exist.");

            SoftwareStatementProfile softwareStatementProfile =
                _softwareStatementProfileService.GetSoftwareStatementProfile(
                    bankClientProfile.SoftwareStatementProfileId);

            TokenEndpointResponse tokenEndpointResponse =
                _mapper.Map <TokenEndpointResponse>(consent.TokenEndpointResponse);

            // Create new Open Banking payment by posting JWT
            OBWriteDomesticConsent4 obConsent        = consent.ObWriteDomesticConsent;
            OBWriteDomestic2        referencePayment = new OBWriteDomestic2
            {
                Data = new OBWriteDomestic2Data
                {
                    ConsentId  = consent.BankId,
                    Initiation = obConsent.Data.Initiation
                },
                Risk = obConsent.Risk
            };

            // Create new Open Banking payment by posting JWT
            OBWriteDomesticResponse4 paymentResponse;

            switch (apiProfile.ApiVersion)
            {
            case ApiVersion.V3P1P1:
                ObModels.PaymentInitiation.V3p1p1.Model.OBWriteDomestic2 newPayment =
                    _mapper.Map <ObModels.PaymentInitiation.V3p1p1.Model.OBWriteDomestic2>(referencePayment);
                OBWriteDomesticResponse2 rawPaymentResponse = await
                                                              PostDomesticPayment <ObModels.PaymentInitiation.V3p1p1.Model.OBWriteDomestic2,
                                                                                   OBWriteDomesticResponse2>(
                    payment : newPayment,
                    apiProfile : apiProfile,
                    softwareStatementProfile : softwareStatementProfile,
                    bankClientProfile : bankClientProfile,
                    tokenEndpointResponse : tokenEndpointResponse);

                paymentResponse = _mapper.Map <OBWriteDomesticResponse4>(rawPaymentResponse);
                break;

            case ApiVersion.V3P1P2:
                throw new ArgumentOutOfRangeException();

            case ApiVersion.V3P1P4:
                paymentResponse = await PostDomesticPayment <OBWriteDomestic2, OBWriteDomesticResponse4>(
                    payment : referencePayment,
                    apiProfile : apiProfile,
                    softwareStatementProfile : softwareStatementProfile,
                    bankClientProfile : bankClientProfile,
                    tokenEndpointResponse : tokenEndpointResponse);

                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            return(paymentResponse);
        }
Exemplo n.º 18
0
        public async Task <PaymentConsentResponse> CreateAsync(DomesticPaymentConsent consent)
        {
            consent.ArgNotNull(nameof(consent));

            // Load relevant objects
            ApiProfile apiProfile = await _apiProfileRepo.GetAsync(consent.ApiProfileId)
                                    ?? throw new KeyNotFoundException("The API Profile does not exist.");

            BankClientProfile bankClientProfile = await _bankClientProfileRepo.GetAsync(apiProfile.BankClientProfileId)
                                                  ?? throw new KeyNotFoundException(
                                                            "The Bank Client Profile does not exist.");

            SoftwareStatementProfile softwareStatementProfile =
                _softwareStatementProfileService.GetSoftwareStatementProfile(
                    bankClientProfile.SoftwareStatementProfileId);

            // Get client credentials grant (we will not cache token for now but simply use to POST consent)
            TokenEndpointResponse tokenEndpointResponse =
                await PostClientCredentialsGrant(scope : "payments", client : bankClientProfile);

            // TODO: validate the response???

            // Create new Open Banking consent by posting JWT
            JwtFactory jwtFactory = new JwtFactory();
            OBWriteDomesticConsentResponse4 consentResponse;

            switch (apiProfile.ApiVersion)
            {
            case ApiVersion.V3P1P1:
                OBWriteDomesticConsent2 newDomesticConsent =
                    _mapper.Map <OBWriteDomesticConsent2>(consent.DomesticConsent);
                OBWriteDomesticConsentResponse2 rawConsentResponse = await
                                                                     PostDomesticConsent <OBWriteDomesticConsent2, OBWriteDomesticConsentResponse2>(
                    jwtFactory : jwtFactory,
                    softwareStatementProfile : softwareStatementProfile,
                    consent : newDomesticConsent,
                    apiProfile : apiProfile,
                    bankClientProfile : bankClientProfile,
                    tokenEndpointResponse : tokenEndpointResponse);

                consentResponse = _mapper.Map <OBWriteDomesticConsentResponse4>(rawConsentResponse);
                break;

            case ApiVersion.V3P1P2:
                throw new ArgumentOutOfRangeException();

            case ApiVersion.V3P1P4:
                consentResponse = await
                                  PostDomesticConsent <OBWriteDomesticConsent4, OBWriteDomesticConsentResponse4>(
                    jwtFactory : jwtFactory,
                    softwareStatementProfile : softwareStatementProfile,
                    consent : consent.DomesticConsent,
                    apiProfile : apiProfile,
                    bankClientProfile : bankClientProfile,
                    tokenEndpointResponse : tokenEndpointResponse);

                break;

            default:
                throw new ArgumentOutOfRangeException();
            }

            // Generate URL for user auth
            string consentId   = consentResponse.Data.ConsentId;
            string redirectUrl = softwareStatementProfile.DefaultFragmentRedirectUrl;

            if (redirectUrl == "")
            {
                redirectUrl = bankClientProfile.BankClientRegistrationClaims.RedirectUris[0];
            }

            OAuth2RequestObjectClaims oAuth2RequestObjectClaims = Factories.CreateOAuth2RequestObjectClaims(
                openBankingClient: bankClientProfile,
                redirectUrl: redirectUrl,
                scope: new[] { "openid", "payments" },
                intentId: consentId);
            string requestObjectJwt = jwtFactory.CreateJwt(
                profile: softwareStatementProfile,
                claims: oAuth2RequestObjectClaims,
                useOpenBankingJwtHeaders: false);
            Dictionary <string, string> keyValuePairs = new Dictionary <string, string>
            {
                { "response_type", oAuth2RequestObjectClaims.ResponseType },
                { "client_id", oAuth2RequestObjectClaims.ClientId },
                { "redirect_uri", oAuth2RequestObjectClaims.RedirectUri },
                { "scope", oAuth2RequestObjectClaims.Scope },
                { "request", requestObjectJwt },
                { "nonce", oAuth2RequestObjectClaims.Nonce },
                { "state", oAuth2RequestObjectClaims.State }
            };
            string queryString = keyValuePairs.ToUrlEncoded();
            string authUrl     = bankClientProfile.OpenIdConfiguration.AuthorizationEndpoint + "?" + queryString;

            // Create and store persistent object
            string          domesticConsentId = Guid.NewGuid().ToString();
            DomesticConsent value             = new DomesticConsent
            {
                State = oAuth2RequestObjectClaims.State,
                SoftwareStatementProfileId = bankClientProfile.SoftwareStatementProfileId,
                IssuerUrl              = bankClientProfile.IssuerUrl,
                ApiProfileId           = apiProfile.Id,
                ObWriteDomesticConsent = consent.DomesticConsent,
                TokenEndpointResponse  = null,
                Id     = domesticConsentId,
                BankId = consentId
            };
            await _domesticConsentRepo.UpsertAsync(value);

            await _dbMultiEntityMethods.SaveChangesAsync();

            return(new PaymentConsentResponse
            {
                AuthUrl = authUrl,
                ConsentId = domesticConsentId
            });
        }