├── example ├── log │ └── .keep ├── tmp │ ├── .keep │ └── pids │ │ └── .keep ├── lib │ ├── tasks │ │ └── .keep │ └── assets │ │ └── .keep ├── storage │ └── .keep ├── vendor │ └── .keep ├── public │ ├── favicon.ico │ ├── apple-touch-icon.png │ ├── apple-touch-icon-precomposed.png │ ├── robots.txt │ ├── 500.html │ ├── 422.html │ └── 404.html ├── test │ ├── helpers │ │ └── .keep │ ├── mailers │ │ └── .keep │ ├── models │ │ └── .keep │ ├── system │ │ └── .keep │ ├── controllers │ │ ├── .keep │ │ ├── home_controller_test.rb │ │ ├── results_controller_test.rb │ │ └── agreements_controller_test.rb │ ├── fixtures │ │ └── files │ │ │ └── .keep │ ├── integration │ │ └── .keep │ ├── application_system_test_case.rb │ ├── channels │ │ └── application_cable │ │ │ └── connection_test.rb │ └── test_helper.rb ├── .ruby-version ├── app │ ├── assets │ │ ├── images │ │ │ └── .keep │ │ ├── config │ │ │ └── manifest.js │ │ └── stylesheets │ │ │ ├── home.scss │ │ │ ├── agreement.scss │ │ │ ├── results.scss │ │ │ └── application.css │ ├── models │ │ ├── concerns │ │ │ └── .keep │ │ └── application_record.rb │ ├── controllers │ │ ├── concerns │ │ │ └── .keep │ │ ├── application_controller.rb │ │ ├── home_controller.rb │ │ ├── agreements_controller.rb │ │ └── results_controller.rb │ ├── helpers │ │ ├── home_helper.rb │ │ ├── results_helper.rb │ │ ├── agreements_helper.rb │ │ └── application_helper.rb │ ├── views │ │ ├── results │ │ │ └── index.html.erb │ │ ├── agreement │ │ │ └── index.html.erb │ │ ├── home │ │ │ └── index.html.erb │ │ └── layouts │ │ │ └── application.html.erb │ ├── channels │ │ └── application_cable │ │ │ ├── channel.rb │ │ │ └── connection.rb │ ├── mailers │ │ └── application_mailer.rb │ ├── javascript │ │ ├── channels │ │ │ ├── index.js │ │ │ └── consumer.js │ │ └── packs │ │ │ └── application.js │ ├── jobs │ │ └── application_job.rb │ └── services │ │ └── client.rb ├── .browserslistrc ├── config │ ├── webpack │ │ ├── environment.js │ │ ├── test.js │ │ ├── development.js │ │ └── production.js │ ├── spring.rb │ ├── environment.rb │ ├── initializers │ │ ├── mime_types.rb │ │ ├── application_controller_renderer.rb │ │ ├── cookies_serializer.rb │ │ ├── filter_parameter_logging.rb │ │ ├── permissions_policy.rb │ │ ├── wrap_parameters.rb │ │ ├── backtrace_silencers.rb │ │ ├── assets.rb │ │ ├── inflections.rb │ │ └── content_security_policy.rb │ ├── boot.rb │ ├── cable.yml │ ├── routes.rb │ ├── credentials.yml.enc │ ├── database.yml │ ├── application.rb │ ├── locales │ │ └── en.yml │ ├── storage.yml │ ├── puma.rb │ ├── webpacker.yml │ └── environments │ │ ├── test.rb │ │ ├── development.rb │ │ └── production.rb ├── resources │ └── _media │ │ ├── f_3_select_aspsp.png │ │ ├── f_4_ng_agreement.jpg │ │ ├── f_5.3_aspsp_auth.jpg │ │ ├── f_6_aspsp_accs.jpg │ │ ├── f_4.1_ng_redirect.png │ │ ├── f_5_aspsps_signin.png │ │ ├── f_5.1_aspsps_signin.jpg │ │ ├── f_5.2_aspsps_signin.jpg │ │ └── f_6.1_aspsp_confirmation.png ├── bin │ ├── rake │ ├── rails │ ├── webpack │ ├── webpack-dev-server │ ├── spring │ ├── yarn │ ├── setup │ └── bundle ├── config.ru ├── Rakefile ├── postcss.config.js ├── .gitattributes ├── db │ └── seeds.rb ├── package.json ├── .gitignore ├── babel.config.js ├── README.md ├── Gemfile └── Gemfile.lock ├── .env.template ├── lib ├── nordigen_ruby │ ├── version.rb │ └── api │ │ ├── institutions.rb │ │ ├── agreements.rb │ │ ├── account.rb │ │ └── requisitions.rb └── nordigen-ruby.rb ├── bin ├── setup └── console ├── .github ├── pull_request_template.md ├── workflows │ └── ci.yml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── Rakefile ├── Gemfile ├── tests ├── test_institution.rb ├── test_client.rb ├── test_account.rb ├── test_requisitions.rb └── test_agreements.rb ├── LICENSE.txt ├── .gitignore ├── CHANGELOG.md ├── nordigen.gemspec ├── main.rb └── README.md /example/log/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/tmp/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/lib/tasks/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/storage/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/tmp/pids/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/vendor/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/lib/assets/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/public/favicon.ico: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/test/helpers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/test/mailers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/test/models/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/test/system/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/.ruby-version: -------------------------------------------------------------------------------- 1 | 3.0.1 2 | -------------------------------------------------------------------------------- /example/app/assets/images/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/app/models/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/test/controllers/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/test/fixtures/files/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/test/integration/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/.browserslistrc: -------------------------------------------------------------------------------- 1 | defaults 2 | -------------------------------------------------------------------------------- /example/app/controllers/concerns/.keep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/public/apple-touch-icon.png: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/app/helpers/home_helper.rb: -------------------------------------------------------------------------------- 1 | module HomeHelper 2 | end 3 | -------------------------------------------------------------------------------- /example/app/helpers/results_helper.rb: -------------------------------------------------------------------------------- 1 | module ResultsHelper 2 | end 3 | -------------------------------------------------------------------------------- /.env.template: -------------------------------------------------------------------------------- 1 | SECRET_ID="YOUR_SECRET_ID" 2 | SECRET_KEY="YOUR_SECRET_KEY" 3 | -------------------------------------------------------------------------------- /example/app/helpers/agreements_helper.rb: -------------------------------------------------------------------------------- 1 | module AgreementsHelper 2 | end 3 | -------------------------------------------------------------------------------- /example/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /example/app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../stylesheets .css 3 | -------------------------------------------------------------------------------- /example/app/views/results/index.html.erb: -------------------------------------------------------------------------------- 1 |

Results#index

2 |

Find me in app/views/results/index.html.erb

3 | -------------------------------------------------------------------------------- /lib/nordigen_ruby/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Nordigen 4 | VERSION = "2.2.1" 5 | end 6 | -------------------------------------------------------------------------------- /example/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | 3 | 4 | end 5 | -------------------------------------------------------------------------------- /example/public/robots.txt: -------------------------------------------------------------------------------- 1 | # See https://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | -------------------------------------------------------------------------------- /example/app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | end 4 | -------------------------------------------------------------------------------- /example/app/views/agreement/index.html.erb: -------------------------------------------------------------------------------- 1 |

Agreements#index

2 |

Find me in app/views/agreement/index.html.erb

3 | -------------------------------------------------------------------------------- /example/config/webpack/environment.js: -------------------------------------------------------------------------------- 1 | const { environment } = require('@rails/webpacker') 2 | 3 | module.exports = environment 4 | -------------------------------------------------------------------------------- /example/app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Channel < ActionCable::Channel::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /example/config/spring.rb: -------------------------------------------------------------------------------- 1 | Spring.watch( 2 | ".ruby-version", 3 | ".rbenv-vars", 4 | "tmp/restart.txt", 5 | "tmp/caching-dev.txt" 6 | ) 7 | -------------------------------------------------------------------------------- /example/resources/_media/f_3_select_aspsp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nordigen/nordigen-ruby/HEAD/example/resources/_media/f_3_select_aspsp.png -------------------------------------------------------------------------------- /example/resources/_media/f_4_ng_agreement.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nordigen/nordigen-ruby/HEAD/example/resources/_media/f_4_ng_agreement.jpg -------------------------------------------------------------------------------- /example/resources/_media/f_5.3_aspsp_auth.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nordigen/nordigen-ruby/HEAD/example/resources/_media/f_5.3_aspsp_auth.jpg -------------------------------------------------------------------------------- /example/resources/_media/f_6_aspsp_accs.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nordigen/nordigen-ruby/HEAD/example/resources/_media/f_6_aspsp_accs.jpg -------------------------------------------------------------------------------- /example/app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Connection < ActionCable::Connection::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /example/resources/_media/f_4.1_ng_redirect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nordigen/nordigen-ruby/HEAD/example/resources/_media/f_4.1_ng_redirect.png -------------------------------------------------------------------------------- /example/resources/_media/f_5_aspsps_signin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nordigen/nordigen-ruby/HEAD/example/resources/_media/f_5_aspsps_signin.png -------------------------------------------------------------------------------- /example/resources/_media/f_5.1_aspsps_signin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nordigen/nordigen-ruby/HEAD/example/resources/_media/f_5.1_aspsps_signin.jpg -------------------------------------------------------------------------------- /example/resources/_media/f_5.2_aspsps_signin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nordigen/nordigen-ruby/HEAD/example/resources/_media/f_5.2_aspsps_signin.jpg -------------------------------------------------------------------------------- /example/app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: 'from@example.com' 3 | layout 'mailer' 4 | end 5 | -------------------------------------------------------------------------------- /example/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | load File.expand_path("spring", __dir__) 3 | require_relative "../config/boot" 4 | require "rake" 5 | Rake.application.run 6 | -------------------------------------------------------------------------------- /example/resources/_media/f_6.1_aspsp_confirmation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nordigen/nordigen-ruby/HEAD/example/resources/_media/f_6.1_aspsp_confirmation.png -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /example/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative "application" 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /example/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative "config/environment" 4 | 5 | run Rails.application 6 | Rails.application.load_server 7 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Related Issue 2 | Issue goes here 3 | 4 | ## Proposed Changes 5 | * Change 1 6 | * Change 2 7 | 8 | ## Additional Info 9 | Any additional information 10 | -------------------------------------------------------------------------------- /example/config/webpack/test.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = process.env.NODE_ENV || 'development' 2 | 3 | const environment = require('./environment') 4 | 5 | module.exports = environment.toWebpackConfig() 6 | -------------------------------------------------------------------------------- /example/config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /example/config/webpack/development.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = process.env.NODE_ENV || 'development' 2 | 3 | const environment = require('./environment') 4 | 5 | module.exports = environment.toWebpackConfig() 6 | -------------------------------------------------------------------------------- /example/config/webpack/production.js: -------------------------------------------------------------------------------- 1 | process.env.NODE_ENV = process.env.NODE_ENV || 'production' 2 | 3 | const environment = require('./environment') 4 | 5 | module.exports = environment.toWebpackConfig() 6 | -------------------------------------------------------------------------------- /example/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | load File.expand_path("spring", __dir__) 3 | APP_PATH = File.expand_path('../config/application', __dir__) 4 | require_relative "../config/boot" 5 | require "rails/commands" 6 | -------------------------------------------------------------------------------- /example/test/application_system_test_case.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class ApplicationSystemTestCase < ActionDispatch::SystemTestCase 4 | driven_by :selenium, using: :chrome, screen_size: [1400, 1400] 5 | end 6 | -------------------------------------------------------------------------------- /example/app/assets/stylesheets/home.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the home controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: https://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rake/testtask" 4 | require "bundler/gem_tasks" 5 | 6 | task default: %i[test] 7 | 8 | Rake::TestTask.new do |t| 9 | t.pattern = "./tests/test_*.rb" 10 | end 11 | -------------------------------------------------------------------------------- /example/app/assets/stylesheets/agreement.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the agreement controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: https://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /example/app/assets/stylesheets/results.scss: -------------------------------------------------------------------------------- 1 | // Place all the styles related to the results controller here. 2 | // They will automatically be included in application.css. 3 | // You can use Sass (SCSS) here: https://sass-lang.com/ 4 | -------------------------------------------------------------------------------- /example/config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 2 | 3 | require "bundler/setup" # Set up gems listed in the Gemfile. 4 | require "bootsnap/setup" # Speed up boot time by caching expensive operations. 5 | -------------------------------------------------------------------------------- /example/test/controllers/home_controller_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class HomeControllerTest < ActionDispatch::IntegrationTest 4 | test "should get index" do 5 | get home_index_url 6 | assert_response :success 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /example/config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: test 6 | 7 | production: 8 | adapter: redis 9 | url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> 10 | channel_prefix: app_production 11 | -------------------------------------------------------------------------------- /example/test/controllers/results_controller_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class ResultsControllerTest < ActionDispatch::IntegrationTest 4 | test "should get index" do 5 | get results_index_url 6 | assert_response :success 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /example/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative "config/application" 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /example/app/javascript/channels/index.js: -------------------------------------------------------------------------------- 1 | // Load all the channels within this directory and all subdirectories. 2 | // Channel files must be named *_channel.js. 3 | 4 | const channels = require.context('.', true, /_channel\.js$/) 5 | channels.keys().forEach(channels) 6 | -------------------------------------------------------------------------------- /example/test/controllers/agreements_controller_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class AgreementControllerTest < ActionDispatch::IntegrationTest 4 | test "should get index" do 5 | get agreement_index_url 6 | assert_response :success 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /example/config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | root 'home#index' 3 | get 'results/', to: 'results#index' 4 | get 'agreements/:id', to: 'agreements#index' 5 | # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html 6 | end 7 | -------------------------------------------------------------------------------- /example/config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ActiveSupport::Reloader.to_prepare do 4 | # ApplicationController.renderer.defaults.merge!( 5 | # http_host: 'example.org', 6 | # https: false 7 | # ) 8 | # end 9 | -------------------------------------------------------------------------------- /example/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /example/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('postcss-import'), 4 | require('postcss-flexbugs-fixes'), 5 | require('postcss-preset-env')({ 6 | autoprefixer: { 7 | flexbox: 'no-2009' 8 | }, 9 | stage: 3 10 | }) 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /example/app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | # Automatically retry jobs that encountered a deadlock 3 | # retry_on ActiveRecord::Deadlocked 4 | 5 | # Most jobs are safe to ignore if the underlying records are no longer available 6 | # discard_on ActiveJob::DeserializationError 7 | end 8 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | # Specify your gem's dependencies in nordigen.gemspec 6 | gemspec 7 | 8 | gem "faraday", "~> 2.5" 9 | 10 | group :development do 11 | gem "rake", "~> 13.0" 12 | gem "test-unit", "~> 3.5.3" 13 | gem "dotenv", "~> 2.8.1" 14 | end 15 | -------------------------------------------------------------------------------- /example/app/javascript/channels/consumer.js: -------------------------------------------------------------------------------- 1 | // Action Cable provides the framework to deal with WebSockets in Rails. 2 | // You can generate new channels where WebSocket features live using the `bin/rails generate channel` command. 3 | 4 | import { createConsumer } from "@rails/actioncable" 5 | 6 | export default createConsumer() 7 | -------------------------------------------------------------------------------- /example/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [ 5 | :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn 6 | ] 7 | -------------------------------------------------------------------------------- /example/app/views/home/index.html.erb: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | × 6 |

Select your bank:

7 |
8 |
9 |
10 | -------------------------------------------------------------------------------- /example/test/channels/application_cable/connection_test.rb: -------------------------------------------------------------------------------- 1 | require "test_helper" 2 | 3 | class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase 4 | # test "connects with cookies" do 5 | # cookies.signed[:user_id] = 42 6 | # 7 | # connect 8 | # 9 | # assert_equal connection.user_id, "42" 10 | # end 11 | end 12 | -------------------------------------------------------------------------------- /example/app/services/client.rb: -------------------------------------------------------------------------------- 1 | require 'nordigen-ruby' 2 | require 'dotenv/load' 3 | 4 | class Client 5 | 6 | def create_client 7 | # Create client instance 8 | return Nordigen::NordigenClient.new( 9 | secret_id: ENV["SECRET_ID"], 10 | secret_key: ENV["SECRET_KEY"] 11 | ) 12 | end 13 | 14 | end 15 | -------------------------------------------------------------------------------- /example/.gitattributes: -------------------------------------------------------------------------------- 1 | # See https://git-scm.com/docs/gitattributes for more about git attribute files. 2 | 3 | # Mark the database schema as having been generated. 4 | db/schema.rb linguist-generated 5 | 6 | # Mark the yarn lockfile as having been generated. 7 | yarn.lock linguist-generated 8 | 9 | # Mark any vendored files as having been vendored. 10 | vendor/* linguist-vendored 11 | -------------------------------------------------------------------------------- /example/db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }]) 7 | # Character.create(name: 'Luke', movie: movies.first) 8 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | require "bundler/setup" 5 | require "nordigen-ruby" 6 | 7 | # You can add fixtures and/or initialization code here to make experimenting 8 | # with your gem easier. You can also use a different console, if you like. 9 | 10 | # (If you use this, don't forget to add pry to your Gemfile!) 11 | # require "pry" 12 | # Pry.start 13 | 14 | require "irb" 15 | IRB.start(__FILE__) 16 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "private": true, 4 | "dependencies": { 5 | "@rails/actioncable": "^6.0.0", 6 | "@rails/activestorage": "^6.0.0", 7 | "@rails/ujs": "^6.0.0", 8 | "@rails/webpacker": "5.4.3", 9 | "turbolinks": "^5.2.0", 10 | "webpack": "^4.46.0", 11 | "webpack-cli": "^3.3.12" 12 | }, 13 | "version": "0.1.0", 14 | "devDependencies": { 15 | "webpack-dev-server": "^3" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /example/test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV['RAILS_ENV'] ||= 'test' 2 | require_relative "../config/environment" 3 | require "rails/test_help" 4 | 5 | class ActiveSupport::TestCase 6 | # Run tests in parallel with specified workers 7 | parallelize(workers: :number_of_processors) 8 | 9 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. 10 | fixtures :all 11 | 12 | # Add more helper methods to be used by all tests here... 13 | end 14 | -------------------------------------------------------------------------------- /example/config/initializers/permissions_policy.rb: -------------------------------------------------------------------------------- 1 | # Define an application-wide HTTP permissions policy. For further 2 | # information see https://developers.google.com/web/updates/2018/06/feature-policy 3 | # 4 | # Rails.application.config.permissions_policy do |f| 5 | # f.camera :none 6 | # f.gyroscope :none 7 | # f.microphone :none 8 | # f.usb :none 9 | # f.fullscreen :self 10 | # f.payment :self, "https://secure.example.com" 11 | # end 12 | -------------------------------------------------------------------------------- /example/config/credentials.yml.enc: -------------------------------------------------------------------------------- 1 | v6+OsrkSuMjyOx9DA0pphX/DtGrFfNo9yKAH6C/AVee/JlbXb16sOPPEG4hwHIorFHaWZMBln9cwhn9gbZKxTG3J1g6fXqFzdXnJcp9b833NPL3BI5xLkE28z9ua8nqL33nIiuaTw3Dbq6j01tKxja/cMTLMvCVzXbWCYmliBr+BPxL5cNaL3RPP2BabTNkiDWtRcZjJFz88sS62y/Sjx1F2d4GDYOtTcc5OSQJ1ShpA9xkH9t9DXSzuuUo9kieesvqZvxJZ6sKccQ0N8qMhi0PFlRVhbsY9plp2+k0WkJgm8mgZtVqubu3/3uXUb3rbZzbhdHY/bMSk84uwhwc8k+HHPaEf0gw8CDx/SdF6CY4XBUYXt8HVIDxCWvWDgUA6mRygEFHbSCcsjVpMhWbA0HyQgouDOHM3oFk+--7UwNIRpqTrlIiylt--u8AnIw1yQXgl3/gDEPXFXQ== -------------------------------------------------------------------------------- /example/bin/webpack: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development" 4 | ENV["NODE_ENV"] ||= "development" 5 | 6 | require "pathname" 7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 8 | Pathname.new(__FILE__).realpath) 9 | 10 | require "bundler/setup" 11 | 12 | require "webpacker" 13 | require "webpacker/webpack_runner" 14 | 15 | APP_ROOT = File.expand_path("..", __dir__) 16 | Dir.chdir(APP_ROOT) do 17 | Webpacker::WebpackRunner.run(ARGV) 18 | end 19 | -------------------------------------------------------------------------------- /example/bin/webpack-dev-server: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development" 4 | ENV["NODE_ENV"] ||= "development" 5 | 6 | require "pathname" 7 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 8 | Pathname.new(__FILE__).realpath) 9 | 10 | require "bundler/setup" 11 | 12 | require "webpacker" 13 | require "webpacker/dev_server_runner" 14 | 15 | APP_ROOT = File.expand_path("..", __dir__) 16 | Dir.chdir(APP_ROOT) do 17 | Webpacker::DevServerRunner.run(ARGV) 18 | end 19 | -------------------------------------------------------------------------------- /example/bin/spring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | if !defined?(Spring) && [nil, "development", "test"].include?(ENV["RAILS_ENV"]) 3 | gem "bundler" 4 | require "bundler" 5 | 6 | # Load Spring without loading other gems in the Gemfile, for speed. 7 | Bundler.locked_gems&.specs&.find { |spec| spec.name == "spring" }&.tap do |spring| 8 | Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path 9 | gem "spring", spring.version 10 | require "spring/binstub" 11 | rescue Gem::LoadError 12 | # Ignore when Spring is not installed. 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /example/app/javascript/packs/application.js: -------------------------------------------------------------------------------- 1 | // This file is automatically compiled by Webpack, along with any other files 2 | // present in this directory. You're encouraged to place your actual application logic in 3 | // a relevant structure within app/javascript and only use these pack files to reference 4 | // that code so it'll be compiled. 5 | 6 | import Rails from "@rails/ujs" 7 | import Turbolinks from "turbolinks" 8 | import * as ActiveStorage from "@rails/activestorage" 9 | import "channels" 10 | 11 | Rails.start() 12 | Turbolinks.start() 13 | ActiveStorage.start() 14 | -------------------------------------------------------------------------------- /example/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /example/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| /my_noisy_library/.match?(line) } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code 7 | # by setting BACKTRACE=1 before calling your invocation, like "BACKTRACE=1 ./bin/rails runner 'MyClass.perform'". 8 | Rails.backtrace_cleaner.remove_silencers! if ENV["BACKTRACE"] 9 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | test: 6 | runs-on: ubuntu-latest 7 | steps: 8 | - uses: actions/checkout@v3 9 | - uses: ruby/setup-ruby@v1 10 | with: 11 | ruby-version: "3.0" # Not needed with a .ruby-version file 12 | bundler-cache: true # runs 'bundle install' and caches installed gems automatically 13 | - run: bundle exec rake 14 | env: 15 | SECRET_ID: ${{ secrets.SECRET_ID }} 16 | SECRET_KEY: ${{ secrets.SECRET_KEY }} 17 | ACCOUNT_ID: ${{ secrets.ACCOUNT_ID }} 18 | -------------------------------------------------------------------------------- /example/bin/yarn: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_ROOT = File.expand_path('..', __dir__) 3 | Dir.chdir(APP_ROOT) do 4 | yarn = ENV["PATH"].split(File::PATH_SEPARATOR). 5 | select { |dir| File.expand_path(dir) != __dir__ }. 6 | product(["yarn", "yarn.cmd", "yarn.ps1"]). 7 | map { |dir, file| File.expand_path(file, dir) }. 8 | find { |file| File.executable?(file) } 9 | 10 | if yarn 11 | exec yarn, *ARGV 12 | else 13 | $stderr.puts "Yarn executable was not detected in the system." 14 | $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" 15 | exit 1 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /example/app/controllers/home_controller.rb: -------------------------------------------------------------------------------- 1 | require_relative "../services/client" 2 | 3 | require "nordigen_ruby/api/institutions" 4 | 5 | class HomeController < ApplicationController 6 | def index 7 | client = Client.new().create_client() 8 | token = client.generate_token()["access"] 9 | 10 | # Get all institutions in specific country 11 | country = "LV" 12 | institution = Nordigen::InstitutionsApi.new(client=client) 13 | institution_list = institution.get_institutions(country) 14 | @list = institution_list.collect {|el| OpenStruct.new(el).marshal_dump }.to_json 15 | 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /example/app/controllers/agreements_controller.rb: -------------------------------------------------------------------------------- 1 | require 'securerandom' 2 | require_relative "../services/client" 3 | 4 | class AgreementsController < ApplicationController 5 | def index 6 | id = params[:id] 7 | 8 | if id == nil 9 | redirect_to '/' 10 | end 11 | 12 | client = Client.new().create_client() 13 | uuid = SecureRandom.uuid 14 | redirect_url = "http://localhost:3000/results/" 15 | init = client.init_session(redirect_url: redirect_url, institution_id: id, reference_id: uuid) 16 | session[:requisition_id] = init["id"] 17 | redirect_to init["link"] 18 | 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/nordigen_ruby/api/institutions.rb: -------------------------------------------------------------------------------- 1 | module Nordigen 2 | class InstitutionsApi 3 | 4 | ENDPOINT = "institutions" 5 | attr_reader :client 6 | 7 | def initialize(client) 8 | # Nordigen client initialization 9 | @client = client 10 | end 11 | 12 | def get_institutions(country) 13 | # Get list of institutions 14 | return client.request.get("#{ENDPOINT}/?country=#{country}").body 15 | end 16 | 17 | def get_institution_by_id(id) 18 | # Get single institution by id 19 | return client.request.get("#{ENDPOINT}/#{id}/").body 20 | end 21 | 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /example/config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path. 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | # Add Yarn node_modules folder to the asset load path. 9 | Rails.application.config.assets.paths << Rails.root.join('node_modules') 10 | 11 | # Precompile additional assets. 12 | # application.js, application.css, and all non-JS/CSS in the app/assets 13 | # folder are already added. 14 | # Rails.application.config.assets.precompile += %w( admin.js admin.css ) 15 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: feature 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /example/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite. Versions 3.8.0 and up are supported. 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: db/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: 20 | <<: *default 21 | database: db/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | database: db/production.sqlite3 26 | -------------------------------------------------------------------------------- /example/config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /example/app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's 6 | * vendor/assets/stylesheets directory can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS 10 | * files in this directory. Styles in this file should be added after the last require_* statement. 11 | * It is generally better to create a new file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | -------------------------------------------------------------------------------- /example/config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative "boot" 2 | 3 | require "rails/all" 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups) 8 | 9 | module App 10 | class Application < Rails::Application 11 | # Initialize configuration defaults for originally generated Rails version. 12 | config.load_defaults 6.1 13 | # Configuration for the application, engines, and railties goes here. 14 | # 15 | # These settings can be overridden in specific environments using the files 16 | # in config/environments, which are processed later. 17 | # 18 | # config.time_zone = "Central Time (US & Canada)" 19 | # config.eager_load_paths << Rails.root.join("extras") 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Specify API endpoint 16 | 2. Specify response & error message 17 | 18 | **Expected behavior** 19 | A clear and concise description of what you expected to happen. 20 | 21 | **Screenshots** 22 | If applicable, add screenshots to help explain your problem. 23 | 24 | **Additional context** 25 | Add any other context about the problem here. 26 | 27 | If you're having general trouble with your Nordigen integration or bank related issue, please reach out to our support via email [bank-account-data-support@gocardless.com](bank-account-data-support@gocardless.com) 28 | -------------------------------------------------------------------------------- /example/app/controllers/results_controller.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | class ResultsController < ApplicationController 4 | def index 5 | client = Client.new().create_client() 6 | requisition_id = session[:requisition_id] 7 | 8 | if !requisition_id 9 | raise "Requisition ID is not found. Please complete authorization with your bank" 10 | end 11 | 12 | requisition_data = client.requisition.get_requisition_by_id(requisition_id) 13 | account_id = requisition_data["accounts"][0] 14 | 15 | account = client.account(account_id) 16 | account_data = [{ 17 | "metadata": account.get_metadata(), 18 | "balances": account.get_balances(), 19 | "details": account.get_details(), 20 | "transactions": account.get_transactions() 21 | }] 22 | 23 | render :json => JSON.pretty_generate(JSON.parse(account_data.to_json)) 24 | 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /example/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # The following keys must be escaped otherwise they will not be retrieved by 20 | # the default I18n backend: 21 | # 22 | # true, false, on, off, yes, no 23 | # 24 | # Instead, surround them with single quotes. 25 | # 26 | # en: 27 | # 'true': 'foo' 28 | # 29 | # To learn more, please read the Rails Internationalization guide 30 | # available at https://guides.rubyonrails.org/i18n.html. 31 | 32 | en: 33 | hello: "Hello world" 34 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore the default SQLite database. 11 | /db/*.sqlite3 12 | /db/*.sqlite3-* 13 | 14 | # Ignore all logfiles and tempfiles. 15 | /log/* 16 | /tmp/* 17 | !/log/.keep 18 | !/tmp/.keep 19 | 20 | # Ignore pidfiles, but keep the directory. 21 | /tmp/pids/* 22 | !/tmp/pids/ 23 | !/tmp/pids/.keep 24 | 25 | # Ignore uploaded files in development. 26 | /storage/* 27 | !/storage/.keep 28 | 29 | /public/assets 30 | .byebug_history 31 | 32 | # Ignore master key for decrypting credentials and more. 33 | /config/master.key 34 | 35 | /public/packs 36 | /public/packs-test 37 | /node_modules 38 | /yarn-error.log 39 | yarn-debug.log* 40 | .yarn-integrity 41 | 42 | # environment 43 | .env 44 | -------------------------------------------------------------------------------- /tests/test_institution.rb: -------------------------------------------------------------------------------- 1 | require 'test/unit' 2 | require 'dotenv/load' 3 | 4 | require_relative '../lib/nordigen-ruby' 5 | require_relative '../lib/nordigen_ruby/api/institutions' 6 | 7 | module Nordigen 8 | 9 | class TestInstitutions < Test::Unit::TestCase 10 | 11 | def setup() 12 | client = NordigenClient.new(secret_id: ENV["SECRET_ID"], secret_key: ENV["SECRET_KEY"]) 13 | client.generate_token() 14 | @institution = InstitutionsApi.new(client=client) 15 | @institution_id = "REVOLUT_REVOGB21" 16 | end 17 | 18 | def test_get_institutions 19 | # Test get list of institutions 20 | institutions = @institution.get_institutions("LV") 21 | id = institutions.collect{ |k,v| k["id"]} 22 | assert_includes(id, @institution_id) 23 | end 24 | 25 | def test_get_institution_by_id 26 | # Test get institution by id 27 | institutions = @institution.get_institution_by_id(id=@institution_id) 28 | assert_equal(institutions["id"], @institution_id) 29 | end 30 | 31 | end 32 | 33 | end 34 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022 SIA "Nordigen Solutions" 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /example/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "fileutils" 3 | 4 | # path to your application root. 5 | APP_ROOT = File.expand_path('..', __dir__) 6 | 7 | def system!(*args) 8 | system(*args) || abort("\n== Command #{args} failed ==") 9 | end 10 | 11 | FileUtils.chdir APP_ROOT do 12 | # This script is a way to set up or update your development environment automatically. 13 | # This script is idempotent, so that you can run it at any time and get an expectable outcome. 14 | # Add necessary setup steps to this file. 15 | 16 | puts '== Installing dependencies ==' 17 | system! 'gem install bundler --conservative' 18 | system('bundle check') || system!('bundle install') 19 | 20 | # Install JavaScript dependencies 21 | system! 'bin/yarn' 22 | 23 | # puts "\n== Copying sample files ==" 24 | # unless File.exist?('config/database.yml') 25 | # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' 26 | # end 27 | 28 | puts "\n== Preparing database ==" 29 | system! 'bin/rails db:prepare' 30 | 31 | puts "\n== Removing old logs and tempfiles ==" 32 | system! 'bin/rails log:clear tmp:clear' 33 | 34 | puts "\n== Restarting application server ==" 35 | system! 'bin/rails restart' 36 | end 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | /.config 4 | /coverage/ 5 | /InstalledFiles 6 | /pkg/ 7 | /spec/reports/ 8 | /spec/examples.txt 9 | /test/tmp/ 10 | /test/version_tmp/ 11 | /tmp/ 12 | 13 | # Used by dotenv library to load environment variables. 14 | .env 15 | 16 | # Ignore Byebug command history file. 17 | .byebug_history 18 | 19 | ## Specific to RubyMotion: 20 | .dat* 21 | .repl_history 22 | build/ 23 | *.bridgesupport 24 | build-iPhoneOS/ 25 | build-iPhoneSimulator/ 26 | 27 | ## Specific to RubyMotion (use of CocoaPods): 28 | # 29 | # We recommend against adding the Pods directory to your .gitignore. However 30 | # you should judge for yourself, the pros and cons are mentioned at: 31 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 32 | # 33 | # vendor/Pods/ 34 | 35 | ## Documentation cache and generated files: 36 | /.yardoc/ 37 | /_yardoc/ 38 | /doc/ 39 | /rdoc/ 40 | 41 | ## Environment normalization: 42 | /.bundle/ 43 | /vendor/bundle 44 | /lib/bundler/man/ 45 | 46 | # for a library or gem, you might want to ignore these files since the code is 47 | # intended to run in multiple environments; otherwise, check them in: 48 | Gemfile.lock 49 | .ruby-version 50 | .ruby-gemset 51 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | 4 | ## [2.2.1] - 2025-04-07 5 | 6 | - Add maintenance notice to README 7 | 8 | ## [2.2.0] - 2024-02-09 9 | 10 | - Change base URL to bankaccountdata.gocardless.com 11 | 12 | ## [2.1.3] - 2023-13-07 13 | 14 | - Update URLs to GoCardless 15 | 16 | ## [2.1.2] - 2022-12-19 17 | 18 | - Fix redirect_immediate parameter 19 | - Add SSN parameter 20 | - Add access_valid_for_days for init method 21 | 22 | ## [2.1.1] - 2022-12-19 23 | 24 | - [add redirect_immediate param #20](https://github.com/nordigen/nordigen-ruby/pull/20) 25 | 26 | 27 | ## [2.1.0] - 2022-12-15 28 | 29 | - [Add user_language and account_selection params for requisition #18](https://github.com/nordigen/nordigen-ruby/pull/18) 30 | - [Add a transactions premium option #19](https://github.com/nordigen/nordigen-ruby/pull/19) 31 | 32 | ## [2.0.1] - 2022-12-09 33 | 34 | - [Fix date filter #15](https://github.com/nordigen/nordigen-ruby/pull/15) 35 | 36 | ## [2.0.0] - 2022-05-05 37 | 38 | - Use JSON response instead of OpenStruct 39 | - Add `date_to`, `date_from` arguments to filter transactions 40 | 41 | 42 | ## [1.0.1] - 2022-01-13 43 | 44 | - Republish library with latest working gem 45 | 46 | ## [1.0.0] - 2022-01-13 47 | 48 | - Initial release 49 | -------------------------------------------------------------------------------- /example/config/storage.yml: -------------------------------------------------------------------------------- 1 | test: 2 | service: Disk 3 | root: <%= Rails.root.join("tmp/storage") %> 4 | 5 | local: 6 | service: Disk 7 | root: <%= Rails.root.join("storage") %> 8 | 9 | # Use rails credentials:edit to set the AWS secrets (as aws:access_key_id|secret_access_key) 10 | # amazon: 11 | # service: S3 12 | # access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> 13 | # secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> 14 | # region: us-east-1 15 | # bucket: your_own_bucket 16 | 17 | # Remember not to checkin your GCS keyfile to a repository 18 | # google: 19 | # service: GCS 20 | # project: your_project 21 | # credentials: <%= Rails.root.join("path/to/gcs.keyfile") %> 22 | # bucket: your_own_bucket 23 | 24 | # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) 25 | # microsoft: 26 | # service: AzureStorage 27 | # storage_account_name: your_account_name 28 | # storage_access_key: <%= Rails.application.credentials.dig(:azure_storage, :storage_access_key) %> 29 | # container: your_container_name 30 | 31 | # mirror: 32 | # service: Mirror 33 | # primary: local 34 | # mirrors: [ amazon, google, microsoft ] 35 | -------------------------------------------------------------------------------- /example/config/initializers/content_security_policy.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Define an application-wide content security policy 4 | # For further information see the following documentation 5 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy 6 | 7 | # Rails.application.config.content_security_policy do |policy| 8 | # policy.default_src :self, :https 9 | # policy.font_src :self, :https, :data 10 | # policy.img_src :self, :https, :data 11 | # policy.object_src :none 12 | # policy.script_src :self, :https 13 | # policy.style_src :self, :https 14 | # # If you are using webpack-dev-server then specify webpack-dev-server host 15 | # policy.connect_src :self, :https, "http://localhost:3035", "ws://localhost:3035" if Rails.env.development? 16 | 17 | # # Specify URI for violation reports 18 | # # policy.report_uri "/csp-violation-report-endpoint" 19 | # end 20 | 21 | # If you are using UJS then enable automatic nonce generation 22 | # Rails.application.config.content_security_policy_nonce_generator = -> request { SecureRandom.base64(16) } 23 | 24 | # Set the nonce only to specific directives 25 | # Rails.application.config.content_security_policy_nonce_directives = %w(script-src) 26 | 27 | # Report CSP violations to a specified URI 28 | # For further information see the following documentation: 29 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only 30 | # Rails.application.config.content_security_policy_report_only = true 31 | -------------------------------------------------------------------------------- /nordigen.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | $LOAD_PATH.unshift(::File.join(::File.dirname(__FILE__), "lib")) 4 | 5 | require "nordigen_ruby/version" 6 | 7 | Gem::Specification.new do |spec| 8 | spec.name = "nordigen-ruby" 9 | spec.version = Nordigen::VERSION 10 | spec.authors = ["Nordigen Solutions"] 11 | spec.email = ["bank-account-data-support@gocardless.com"] 12 | spec.summary = "Nordigen client for Ruby" 13 | spec.homepage = "https://github.com/nordigen/nordigen-ruby" 14 | spec.description = "Nordigen official API client for Ruby" 15 | spec.license = "MIT" 16 | spec.required_ruby_version = ">= 2.6.0" 17 | 18 | spec.metadata["homepage_uri"] = "https://github.com/nordigen/nordigen-ruby" 19 | spec.metadata["bug_tracker_uri"] = "https://github.com/nordigen/nordigen-ruby/issues" 20 | spec.metadata["changelog_uri"] = "https://github.com/nordigen/nordigen-ruby/blob/master/CHANGELOG.md" 21 | spec.metadata["documentation_uri"] = "https://github.com/nordigen/nordigen-ruby" 22 | spec.metadata["github_repo"] = "https://github.com/nordigen/nordigen-ruby" 23 | spec.metadata["source_code_uri"] = "https://github.com/nordigen/nordigen-ruby" 24 | 25 | ignored = Regexp.union( 26 | /\A\.env.template/, 27 | /\A\.git/, 28 | /\Atest/, 29 | /\Aexample/, 30 | /\Amain.rb/ 31 | ) 32 | spec.files = `git ls-files`.split("\n").reject { |f| ignored.match(f) } 33 | spec.executables = `git ls-files -- bin/*`.split("\n") 34 | .map { |f| ::File.basename(f) } 35 | 36 | spec.add_dependency "faraday", "~> 2.5" 37 | 38 | spec.require_paths = ["lib"] 39 | 40 | end 41 | -------------------------------------------------------------------------------- /tests/test_client.rb: -------------------------------------------------------------------------------- 1 | require 'test/unit' 2 | require 'dotenv/load' 3 | require 'securerandom' 4 | 5 | require_relative '../lib/nordigen-ruby' 6 | require_relative '../lib/nordigen_ruby/api/institutions' 7 | 8 | module Nordigen 9 | 10 | class TestClient < Test::Unit::TestCase 11 | 12 | def setup() 13 | @client = NordigenClient.new(secret_id: ENV["SECRET_ID"], secret_key: ENV["SECRET_KEY"]) 14 | end 15 | 16 | def test_set_get_token 17 | # Test setter and getter for token 18 | new_token = "New token value" 19 | @client.set_token(new_token) 20 | token = @client.get_token() 21 | assert_equal(token, "Bearer #{new_token}") 22 | end 23 | 24 | def test_generate_token 25 | # Test generate new token 26 | response = @client.generate_token() 27 | assert_equal(response["access_expires"], 86400) 28 | end 29 | 30 | 31 | def test_exchange_token 32 | # Test exchange token 33 | refresh_token = @client.generate_token()["refresh"] 34 | response = @client.exchange_token(refresh_token) 35 | assert_equal(response["access_expires"], 86400) 36 | end 37 | 38 | def test_init_session 39 | # Test initialize session 40 | uuid = SecureRandom.uuid 41 | id = "REVOLUT_REVOGB21" 42 | response = @client.init_session( 43 | redirect_url: "https://gocardless.com", institution_id: id, reference_id: uuid 44 | ) 45 | assert_equal(response["institution_id"], id) 46 | 47 | end 48 | 49 | end 50 | 51 | end 52 | -------------------------------------------------------------------------------- /lib/nordigen_ruby/api/agreements.rb: -------------------------------------------------------------------------------- 1 | module Nordigen 2 | class AgreementsApi 3 | 4 | ENDPOINT = "agreements/enduser/" 5 | attr_reader :client 6 | 7 | def initialize(client) 8 | # Nordigen client initialization 9 | @client = client 10 | end 11 | 12 | def create_agreement(institution_id:, max_historical_days: 90, access_valid_for_days: 90, access_scope: [ 13 | "balances", 14 | "details", 15 | "transactions" 16 | ]) 17 | # Create enduser agreement 18 | payload = { 19 | "institution_id": institution_id, 20 | "max_historical_days": max_historical_days, 21 | "access_valid_for_days": access_valid_for_days, 22 | "access_scope": access_scope, 23 | }; 24 | return client.request.post(ENDPOINT, payload).body 25 | end 26 | 27 | 28 | def get_agreements(limit: 100, offset: 0) 29 | # Get list of agreements 30 | params = {limit: limit, offset: offset} 31 | return client.request.get(ENDPOINT, params).body 32 | end 33 | 34 | def get_agreement_by_id(agreement_id) 35 | # Get agreemenet by id 36 | return client.request.get("#{ENDPOINT}#{agreement_id}/").body 37 | end 38 | 39 | def delete_agreement(agreement_id) 40 | # Delete agreement by id 41 | return client.request.delete("#{ENDPOINT}#{agreement_id}/").body 42 | end 43 | 44 | def accept_agreement(agreement_id:, ip:, user_agent:) 45 | # Accept end user agreement 46 | payload = { 47 | 'user_agent': user_agent, 48 | 'ip_address': ip 49 | } 50 | return client.request.put("#{ENDPOINT}#{agreement_id}/accept/").body 51 | end 52 | 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /example/public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /lib/nordigen_ruby/api/account.rb: -------------------------------------------------------------------------------- 1 | module Nordigen 2 | class AccountApi 3 | 4 | ENDPOINT = "accounts/" 5 | PREMIUM_ENDPOINT = "accounts/premium/" 6 | attr_reader :client, :account_id 7 | 8 | def initialize(client:, account_id:) 9 | @client = client 10 | @account_id = account_id 11 | end 12 | 13 | def get(path = nil, params = nil, premium: nil) 14 | # Create Get request 15 | if premium 16 | url = "#{PREMIUM_ENDPOINT}#{@account_id}/" 17 | else 18 | url = "#{ENDPOINT}#{@account_id}/" 19 | end 20 | 21 | if path 22 | url = "#{url}#{path}/" 23 | end 24 | 25 | return client.request.get(url, params).body 26 | end 27 | 28 | def get_metadata 29 | # Access account metadata 30 | return get() 31 | end 32 | 33 | def get_details 34 | # Access account details 35 | return get("details") 36 | end 37 | 38 | 39 | def get_balances 40 | # Access account balances 41 | return get("balances") 42 | end 43 | 44 | def get_transactions(date_from: nil, date_to: nil) 45 | # Access account transactions 46 | date_range = { 47 | "date_from" => date_from, 48 | "date_to" => date_to 49 | } 50 | return get("transactions", date_range) 51 | end 52 | 53 | def get_premium_transactions(date_from: nil, date_to: nil, country: nil) 54 | # Access account transactions 55 | params = { 56 | "date_from" => date_from, 57 | "date_to" => date_to, 58 | "country" => country 59 | } 60 | return get("transactions", params, premium: true ) 61 | end 62 | 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /example/config/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers: a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum; this matches the default thread size of Active Record. 6 | # 7 | max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } 8 | min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } 9 | threads min_threads_count, max_threads_count 10 | 11 | # Specifies the `worker_timeout` threshold that Puma will use to wait before 12 | # terminating a worker in development environments. 13 | # 14 | worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" 15 | 16 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 17 | # 18 | port ENV.fetch("PORT") { 3000 } 19 | 20 | # Specifies the `environment` that Puma will run in. 21 | # 22 | environment ENV.fetch("RAILS_ENV") { "development" } 23 | 24 | # Specifies the `pidfile` that Puma will use. 25 | pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } 26 | 27 | # Specifies the number of `workers` to boot in clustered mode. 28 | # Workers are forked web server processes. If using threads and workers together 29 | # the concurrency of the application would be max `threads` * `workers`. 30 | # Workers do not work on JRuby or Windows (both of which do not support 31 | # processes). 32 | # 33 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 34 | 35 | # Use the `preload_app!` method when specifying a `workers` number. 36 | # This directive tells Puma to first boot the application and load code 37 | # before forking the application. This takes advantage of Copy On Write 38 | # process behavior so workers use less memory. 39 | # 40 | # preload_app! 41 | 42 | # Allow puma to be restarted by `rails restart` command. 43 | plugin :tmp_restart 44 | -------------------------------------------------------------------------------- /tests/test_account.rb: -------------------------------------------------------------------------------- 1 | require 'test/unit' 2 | require 'dotenv/load' 3 | 4 | require_relative '../lib/nordigen_ruby/api/account' 5 | require_relative '../lib/nordigen-ruby' 6 | 7 | module Nordigen 8 | 9 | class TestAccount < Test::Unit::TestCase 10 | 11 | def setup() 12 | # Would it be possible to add a sandbox account 13 | # to the SANDBOXFINANCE_SFIN0000 institution, 14 | # that is always authorized? 15 | omit('Not yet possible to test in CI') 16 | 17 | client = NordigenClient.new(secret_id: ENV["SECRET_ID"], secret_key: ENV["SECRET_KEY"]) 18 | client.generate_token() 19 | @account = AccountApi.new(client: client, account_id: ENV["ACCOUNT_ID"]) 20 | @institution_id = "REVOLUT_REVOGB21" 21 | end 22 | 23 | def test_account_metadata 24 | # Test get account metadata 25 | response = @account.get_metadata() 26 | assert_equal(response["institution_id"], @institution_id) 27 | end 28 | 29 | 30 | def test_account_details 31 | # Test get account details 32 | response = @account.get_details() 33 | assert_equal(response["account"]["currency"], "EUR") 34 | end 35 | 36 | def test_account_balances 37 | # Test get account balances 38 | response = @account.get_balances() 39 | currency = response["balances"][0]["balanceAmount"]["currency"] 40 | assert_equal(currency, "EUR") 41 | end 42 | 43 | def test_account_transactions 44 | # Test get account transactions 45 | response = @account.get_transactions() 46 | assert_equal(response["booked"], nil) 47 | end 48 | 49 | def test_account_transactions_with_date_range 50 | omit('Need a test account with enough transactions to filter by date to test this') 51 | end 52 | 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /main.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'securerandom' 3 | require_relative "lib/nordigen-ruby" 4 | 5 | module Nordigen 6 | # Load token from .env file or replace with a string value 7 | # Secrets can be generated from bankaccountdata.gocardless.com/user-secrets/ portal 8 | client = Nordigen::NordigenClient.new( 9 | secret_id: "SECRET_ID", 10 | secret_key: "SECRET_KEY" 11 | ) 12 | 13 | # Generate token 14 | token_data = client.generate_token() 15 | refresh_token = token_data["refresh"] 16 | 17 | # Exchange token 18 | # new_token = client.exchange_token(access_token) 19 | 20 | # Use existing token 21 | # client.set_token("YOUR_TOKEN") 22 | 23 | # Get all institution by providing country code in ISO 3166 format 24 | institutions = client.institution.get_institutions("LV") 25 | 26 | # Institution id can be gathered from get_institutions response. Example Revolut id 27 | id = "REVOLUT_REVOGB21" 28 | 29 | # Initialize bank authorization session 30 | init = client.init_session( 31 | redirect_url: "https://bankaccountdata.gocardless.com", 32 | institution_id: id, 33 | reference_id: SecureRandom.uuid, 34 | user_language: "en", 35 | ) 36 | requisition_id = init["id"] 37 | puts init["link"] 38 | 39 | # Get account id after you have completed authorization with a bank 40 | accounts = client.requisition.get_requisition_by_id(requisition_id) 41 | 42 | begin 43 | # Get account id from list 44 | account_id = accounts["accounts"][0] 45 | rescue 46 | puts "Account list is empty. Make sure you have completed authorization with a bank." 47 | end 48 | 49 | # # Get account data 50 | account = client.account(account_id) 51 | 52 | meta = account.get_metadata() 53 | details = account.get_details() 54 | balances = account.get_balances() 55 | transactions = account.get_transactions() 56 | 57 | end 58 | -------------------------------------------------------------------------------- /example/public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /example/public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /tests/test_requisitions.rb: -------------------------------------------------------------------------------- 1 | require 'test/unit' 2 | require 'dotenv/load' 3 | require 'securerandom' 4 | 5 | require_relative '../lib/nordigen-ruby' 6 | require_relative '../lib/nordigen_ruby/api/requisitions' 7 | 8 | module Nordigen 9 | 10 | class TestRequisitions < Test::Unit::TestCase 11 | 12 | def setup() 13 | client = NordigenClient.new(secret_id: ENV["SECRET_ID"], secret_key: ENV["SECRET_KEY"]) 14 | client.generate_token() 15 | @requisition = RequisitionsApi.new(client=client) 16 | 17 | @institution_id = "REVOLUT_REVOGB21" 18 | @req_params = { 19 | redirect_url: "https://bankaccountdata.gocardless.com", 20 | reference: SecureRandom.uuid, 21 | institution_id: @institution_id 22 | } 23 | end 24 | 25 | def test_create_requisition 26 | # Test create requisition 27 | uuid = SecureRandom.uuid 28 | response = @requisition.create_requisition(**@req_params) 29 | assert_equal(response["institution_id"], @institution_id) 30 | end 31 | 32 | def test_get_requisitions 33 | # Test get list of requisitions 34 | response = @requisition.get_requisitions() 35 | assert_equal(response["previous"], nil) 36 | end 37 | 38 | def test_get_requisition_by_id 39 | # Test get requisition by id 40 | new_requisition = @requisition.create_requisition(**@req_params) 41 | id = new_requisition["id"] 42 | response = @requisition.get_requisition_by_id(id) 43 | assert_equal(response["id"], id) 44 | end 45 | 46 | def test_delete_requisition 47 | # Test delete requisition 48 | new_requisition = @requisition.create_requisition(**@req_params) 49 | id = new_requisition["id"] 50 | response = @requisition.delete_requisition(id) 51 | assert_equal(response["summary"], "Requisition deleted") 52 | end 53 | 54 | end 55 | 56 | end 57 | -------------------------------------------------------------------------------- /lib/nordigen_ruby/api/requisitions.rb: -------------------------------------------------------------------------------- 1 | module Nordigen 2 | class RequisitionsApi 3 | 4 | ENDPOINT = "requisitions/" 5 | attr_reader :client 6 | 7 | def initialize(client) 8 | # Nordigen client initialization 9 | @client = client 10 | end 11 | 12 | def create_requisition( 13 | redirect_url:, 14 | reference:, 15 | institution_id:, 16 | user_language: "en", 17 | agreement: nil, 18 | account_selection: false, 19 | redirect_immediate: false, 20 | ssn: nil 21 | ) 22 | # Create requisition. For creating links and retrieving accounts. 23 | # puts account_selection 24 | # puts redirect_immediate 25 | payload = { 26 | "redirect": redirect_url, 27 | "reference": reference, 28 | "institution_id": institution_id, 29 | "user_language": user_language, 30 | "account_selection": account_selection, 31 | "redirect_immediate": redirect_immediate, 32 | } 33 | 34 | if agreement 35 | payload["agreement"] = agreement 36 | end 37 | 38 | if ssn 39 | payload["ssn"] = ssn 40 | end 41 | 42 | return client.request.post(ENDPOINT, payload).body 43 | end 44 | 45 | def get_requisitions(limit: 100, offset: 0) 46 | # Get all requisitions 47 | params = {limit: limit, offset: offset} 48 | return client.request.get(ENDPOINT, params).body 49 | end 50 | 51 | 52 | def get_requisition_by_id(requisition_id) 53 | # Get requisition by id 54 | return client.request.get("#{ENDPOINT}#{requisition_id}/").body 55 | end 56 | 57 | def delete_requisition(requisition_id) 58 | # Delete requisition by id 59 | return client.request.delete("#{ENDPOINT}#{requisition_id}/").body 60 | end 61 | 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /example/config/webpacker.yml: -------------------------------------------------------------------------------- 1 | # Note: You must restart bin/webpack-dev-server for changes to take effect 2 | 3 | default: &default 4 | source_path: app/javascript 5 | source_entry_path: packs 6 | public_root_path: public 7 | public_output_path: packs 8 | cache_path: tmp/cache/webpacker 9 | webpack_compile_output: true 10 | 11 | # Additional paths webpack should lookup modules 12 | # ['app/assets', 'engine/foo/app/assets'] 13 | additional_paths: [] 14 | 15 | # Reload manifest.json on all requests so we reload latest compiled packs 16 | cache_manifest: false 17 | 18 | # Extract and emit a css file 19 | extract_css: false 20 | 21 | static_assets_extensions: 22 | - .jpg 23 | - .jpeg 24 | - .png 25 | - .gif 26 | - .tiff 27 | - .ico 28 | - .svg 29 | - .eot 30 | - .otf 31 | - .ttf 32 | - .woff 33 | - .woff2 34 | 35 | extensions: 36 | - .mjs 37 | - .js 38 | - .sass 39 | - .scss 40 | - .css 41 | - .module.sass 42 | - .module.scss 43 | - .module.css 44 | - .png 45 | - .svg 46 | - .gif 47 | - .jpeg 48 | - .jpg 49 | 50 | development: 51 | <<: *default 52 | compile: true 53 | 54 | # Reference: https://webpack.js.org/configuration/dev-server/ 55 | dev_server: 56 | https: false 57 | host: localhost 58 | port: 3035 59 | public: localhost:3035 60 | hmr: false 61 | # Inline should be set to true if using HMR 62 | inline: true 63 | overlay: true 64 | compress: true 65 | disable_host_check: true 66 | use_local_ip: false 67 | quiet: false 68 | pretty: false 69 | headers: 70 | 'Access-Control-Allow-Origin': '*' 71 | watch_options: 72 | ignored: '**/node_modules/**' 73 | 74 | 75 | test: 76 | <<: *default 77 | compile: true 78 | 79 | # Compile test packs to a separate directory 80 | public_output_path: packs-test 81 | 82 | production: 83 | <<: *default 84 | 85 | # Production depends on precompilation of packs prior to booting for performance. 86 | compile: false 87 | 88 | # Extract and emit a css file 89 | extract_css: true 90 | 91 | # Cache manifest.json for performance 92 | cache_manifest: true 93 | -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | var validEnv = ['development', 'test', 'production'] 3 | var currentEnv = api.env() 4 | var isDevelopmentEnv = api.env('development') 5 | var isProductionEnv = api.env('production') 6 | var isTestEnv = api.env('test') 7 | 8 | if (!validEnv.includes(currentEnv)) { 9 | throw new Error( 10 | 'Please specify a valid `NODE_ENV` or ' + 11 | '`BABEL_ENV` environment variables. Valid values are "development", ' + 12 | '"test", and "production". Instead, received: ' + 13 | JSON.stringify(currentEnv) + 14 | '.' 15 | ) 16 | } 17 | 18 | return { 19 | presets: [ 20 | isTestEnv && [ 21 | '@babel/preset-env', 22 | { 23 | targets: { 24 | node: 'current' 25 | } 26 | } 27 | ], 28 | (isProductionEnv || isDevelopmentEnv) && [ 29 | '@babel/preset-env', 30 | { 31 | forceAllTransforms: true, 32 | useBuiltIns: 'entry', 33 | corejs: 3, 34 | modules: false, 35 | exclude: ['transform-typeof-symbol'] 36 | } 37 | ] 38 | ].filter(Boolean), 39 | plugins: [ 40 | 'babel-plugin-macros', 41 | '@babel/plugin-syntax-dynamic-import', 42 | isTestEnv && 'babel-plugin-dynamic-import-node', 43 | '@babel/plugin-transform-destructuring', 44 | [ 45 | '@babel/plugin-proposal-class-properties', 46 | { 47 | loose: true 48 | } 49 | ], 50 | [ 51 | '@babel/plugin-proposal-object-rest-spread', 52 | { 53 | useBuiltIns: true 54 | } 55 | ], 56 | [ 57 | '@babel/plugin-proposal-private-methods', 58 | { 59 | loose: true 60 | } 61 | ], 62 | [ 63 | '@babel/plugin-proposal-private-property-in-object', 64 | { 65 | loose: true 66 | } 67 | ], 68 | [ 69 | '@babel/plugin-transform-runtime', 70 | { 71 | helpers: false 72 | } 73 | ], 74 | [ 75 | '@babel/plugin-transform-regenerator', 76 | { 77 | async: false 78 | } 79 | ] 80 | ].filter(Boolean) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Nordigen Ruby example app with Ruby on Rails 2 | 3 | ## Set-up 4 | --- 5 | You'll need to get your `SECRET_ID` and `SECRET_KEY` from the [GoCardless Bank Account Data portal](https://bankaccountdata.gocardless.com/user-secrets/). 6 | In **app.py** file provide the token as a parameter for `NordigenClient`. 7 | 8 | ```ruby 9 | # Init Nordigen client 10 | # In services/ directory you can modify secret_id & secret_key or store the values in .env file 11 | client = Nordigen::NordigenClient.new( 12 | secret_id: ENV["SECRET_ID"], 13 | secret_key: ENV["SECRET_KEY"] 14 | ) 15 | ``` 16 | 17 | To initialize session with a bank, you have to specify `country` (a two-letter country code) and your `redirect_uri`. 18 | In `controllers/home_controller.rb` directory, modify `country` value. 19 | ```ruby 20 | country = 'LV' 21 | ``` 22 | 23 | In `agreements.controller.rb` modify your `redirect_uri` value. 24 | ```ruby 25 | redirect_url = "http://localhost:3000/results/" 26 | ``` 27 | 28 | ## Installation 29 | --- 30 | Install dependencies 31 | 32 | ```bash 33 | bundle install 34 | ``` 35 | 36 | Start Rails app 37 | 38 | ```bash 39 | rails s 40 | ``` 41 | 42 | Below is an example of the authentication process with Revolut. 43 | 44 | ### 1. Go to http://localhost:3000/ and select bank 45 |

46 | 47 |

48 | 49 | ### 2. Provide consent 50 |

51 | 52 | 53 |

54 | 55 | ### 3. Sign into bank (Institution) 56 |

57 | 58 | 59 | 60 |

61 | 62 |

63 | 64 |

65 | 66 | ### 4. Select accounts 67 |

68 | 69 |

70 | 71 | ### 5. You will be redirected to specified `redirect_uri` in our case it is `http://localhost:5000/` where details, balances and transactions will be returned from your bank account. 72 | -------------------------------------------------------------------------------- /example/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" } 3 | 4 | ruby '3.0.1' 5 | 6 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails', branch: 'main' 7 | gem 'rails', '~> 6.1.4', '>= 6.1.4.1' 8 | # Use sqlite3 as the database for Active Record 9 | gem 'sqlite3', '~> 1.4' 10 | # Use Puma as the app server 11 | gem 'puma', '~> 5.0' 12 | # Use SCSS for stylesheets 13 | gem 'sass-rails', '>= 6' 14 | # Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker 15 | gem 'webpacker', '~> 5.0' 16 | # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks 17 | gem 'turbolinks', '~> 5' 18 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder 19 | gem 'jbuilder', '~> 2.7' 20 | gem 'dotenv' 21 | 22 | gem 'nordigen-ruby', '~> 2.1.2' 23 | 24 | # Local gem 25 | # gem 'nordigen-ruby', path: '../' 26 | 27 | # Use Active Storage variant 28 | # gem 'image_processing', '~> 1.2' 29 | 30 | # Reduces boot times through caching; required in config/boot.rb 31 | gem 'bootsnap', '>= 1.4.4', require: false 32 | 33 | group :development, :test do 34 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console 35 | gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] 36 | end 37 | 38 | group :development do 39 | # Access an interactive console on exception pages or by calling 'console' anywhere in the code. 40 | gem 'web-console', '>= 4.1.0' 41 | # Display performance information such as SQL time and flame graphs for each request in your browser. 42 | # Can be configured to work on production as well see: https://github.com/MiniProfiler/rack-mini-profiler/blob/master/README.md 43 | gem 'rack-mini-profiler', '~> 2.0' 44 | gem 'listen', '~> 3.3' 45 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring 46 | gem 'spring' 47 | end 48 | 49 | group :test do 50 | # Adds support for Capybara system testing and selenium driver 51 | gem 'capybara', '>= 3.26' 52 | gem 'selenium-webdriver' 53 | # Easy installation and use of web drivers to run system tests with browsers 54 | gem 'webdrivers' 55 | end 56 | 57 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem 58 | gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] 59 | -------------------------------------------------------------------------------- /tests/test_agreements.rb: -------------------------------------------------------------------------------- 1 | require 'test/unit' 2 | require 'dotenv/load' 3 | 4 | require_relative '../lib/nordigen-ruby' 5 | require_relative "../lib/nordigen_ruby/api/agreements" 6 | 7 | module Nordigen 8 | 9 | class TestAgreements < Test::Unit::TestCase 10 | 11 | def setup() 12 | client = NordigenClient.new(secret_id: ENV["SECRET_ID"], secret_key: ENV["SECRET_KEY"]) 13 | client.generate_token() 14 | @agreement = AgreementsApi.new(client=client) 15 | @institution_id = "REVOLUT_REVOGB21" 16 | end 17 | 18 | def test_create_agreement 19 | # Test create agreement 20 | response = @agreement.create_agreement(institution_id: @institution_id) 21 | assert_equal(response["institution_id"], @institution_id) 22 | end 23 | 24 | 25 | def test_get_agreement_by_id 26 | # Test Get agreement by id 27 | create_agreement = @agreement.create_agreement(institution_id: @institution_id) 28 | agreement_id = create_agreement["id"] 29 | response = @agreement.get_agreement_by_id(agreement_id) 30 | assert_equal(response["id"], agreement_id) 31 | end 32 | 33 | def test_get_agreements 34 | # Test Get list of agreements 35 | response = @agreement.get_agreements() 36 | assert_equal(response["previous"], nil) 37 | end 38 | 39 | def test_delete_agreement 40 | # Test delete agreement 41 | create_agreement = @agreement.create_agreement(institution_id: @institution_id) 42 | agreement_id = create_agreement["id"] 43 | response = @agreement.delete_agreement(agreement_id) 44 | assert_equal(response["summary"], "End User Agreement deleted") 45 | end 46 | 47 | def test_accept_agreement 48 | # Test accept agreement 49 | omit('Available only for premium users') 50 | create_agreement = @agreement.create_agreement(institution_id: @institution_id) 51 | agreement_id = create_agreement["id"] 52 | response = @agreement.accept_agreement( 53 | user_agent: "Chrome", 54 | ip: "127.0.0.1", 55 | agreement_id: agreement_id 56 | ) 57 | assert_equal(response["id"], agreement_id) 58 | end 59 | 60 | end 61 | 62 | end 63 | -------------------------------------------------------------------------------- /example/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | # The test environment is used exclusively to run your application's 4 | # test suite. You never need to work with it otherwise. Remember that 5 | # your test database is "scratch space" for the test suite and is wiped 6 | # and recreated between test runs. Don't rely on the data there! 7 | 8 | Rails.application.configure do 9 | # Settings specified here will take precedence over those in config/application.rb. 10 | 11 | config.cache_classes = false 12 | config.action_view.cache_template_loading = true 13 | 14 | # Do not eager load code on boot. This avoids loading your whole application 15 | # just for the purpose of running a single test. If you are using a tool that 16 | # preloads Rails for running tests, you may have to set it to true. 17 | config.eager_load = false 18 | 19 | # Configure public file server for tests with Cache-Control for performance. 20 | config.public_file_server.enabled = true 21 | config.public_file_server.headers = { 22 | 'Cache-Control' => "public, max-age=#{1.hour.to_i}" 23 | } 24 | 25 | # Show full error reports and disable caching. 26 | config.consider_all_requests_local = true 27 | config.action_controller.perform_caching = false 28 | config.cache_store = :null_store 29 | 30 | # Raise exceptions instead of rendering exception templates. 31 | config.action_dispatch.show_exceptions = false 32 | 33 | # Disable request forgery protection in test environment. 34 | config.action_controller.allow_forgery_protection = false 35 | 36 | # Store uploaded files on the local file system in a temporary directory. 37 | config.active_storage.service = :test 38 | 39 | config.action_mailer.perform_caching = false 40 | 41 | # Tell Action Mailer not to deliver emails to the real world. 42 | # The :test delivery method accumulates sent emails in the 43 | # ActionMailer::Base.deliveries array. 44 | config.action_mailer.delivery_method = :test 45 | 46 | # Print deprecation notices to the stderr. 47 | config.active_support.deprecation = :stderr 48 | 49 | # Raise exceptions for disallowed deprecations. 50 | config.active_support.disallowed_deprecation = :raise 51 | 52 | # Tell Active Support which deprecation messages to disallow. 53 | config.active_support.disallowed_deprecation_warnings = [] 54 | 55 | # Raises error for missing translations. 56 | # config.i18n.raise_on_missing_translations = true 57 | 58 | # Annotate rendered view with file names. 59 | # config.action_view.annotate_rendered_view_with_filenames = true 60 | end 61 | -------------------------------------------------------------------------------- /example/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Nordigen Rails app 5 | 6 | <%= csrf_meta_tags %> 7 | <%= csp_meta_tag %> 8 | 9 | 10 | 11 | 12 | 13 | <%= yield %> 14 | 15 | <%= content_tag :div, class: "institution_list", data: {institutions: @list} do %> 16 | <% end %> 17 | 18 | 19 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /example/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # In the development environment your application's code is reloaded any time 7 | # it changes. This slows down response time but is perfect for development 8 | # since you don't have to restart the web server when you make code changes. 9 | config.cache_classes = false 10 | 11 | # Do not eager load code on boot. 12 | config.eager_load = false 13 | 14 | # Show full error reports. 15 | config.consider_all_requests_local = true 16 | 17 | # Enable/disable caching. By default caching is disabled. 18 | # Run rails dev:cache to toggle caching. 19 | if Rails.root.join('tmp', 'caching-dev.txt').exist? 20 | config.action_controller.perform_caching = true 21 | config.action_controller.enable_fragment_cache_logging = true 22 | 23 | config.cache_store = :memory_store 24 | config.public_file_server.headers = { 25 | 'Cache-Control' => "public, max-age=#{2.days.to_i}" 26 | } 27 | else 28 | config.action_controller.perform_caching = false 29 | 30 | config.cache_store = :null_store 31 | end 32 | 33 | # Store uploaded files on the local file system (see config/storage.yml for options). 34 | config.active_storage.service = :local 35 | 36 | # Don't care if the mailer can't send. 37 | config.action_mailer.raise_delivery_errors = false 38 | 39 | config.action_mailer.perform_caching = false 40 | 41 | # Print deprecation notices to the Rails logger. 42 | config.active_support.deprecation = :log 43 | 44 | # Raise exceptions for disallowed deprecations. 45 | config.active_support.disallowed_deprecation = :raise 46 | 47 | # Tell Active Support which deprecation messages to disallow. 48 | config.active_support.disallowed_deprecation_warnings = [] 49 | 50 | # Raise an error on page load if there are pending migrations. 51 | config.active_record.migration_error = :page_load 52 | 53 | # Highlight code that triggered database queries in logs. 54 | config.active_record.verbose_query_logs = true 55 | 56 | # Debug mode disables concatenation and preprocessing of assets. 57 | # This option may cause significant delays in view rendering with a large 58 | # number of complex assets. 59 | config.assets.debug = true 60 | 61 | # Suppress logger output for asset requests. 62 | config.assets.quiet = true 63 | 64 | # Raises error for missing translations. 65 | # config.i18n.raise_on_missing_translations = true 66 | 67 | # Annotate rendered view with file names. 68 | # config.action_view.annotate_rendered_view_with_filenames = true 69 | 70 | # Use an evented file watcher to asynchronously detect changes in source code, 71 | # routes, locales, etc. This feature depends on the listen gem. 72 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker 73 | 74 | # Uncomment if you wish to allow Action Cable access from any origin. 75 | # config.action_cable.disable_request_forgery_protection = true 76 | end 77 | -------------------------------------------------------------------------------- /example/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | 4 | # 5 | # This file was generated by Bundler. 6 | # 7 | # The application 'bundle' is installed as part of a gem, and 8 | # this file is here to facilitate running it. 9 | # 10 | 11 | require "rubygems" 12 | 13 | m = Module.new do 14 | module_function 15 | 16 | def invoked_as_script? 17 | File.expand_path($0) == File.expand_path(__FILE__) 18 | end 19 | 20 | def env_var_version 21 | ENV["BUNDLER_VERSION"] 22 | end 23 | 24 | def cli_arg_version 25 | return unless invoked_as_script? # don't want to hijack other binstubs 26 | return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update` 27 | bundler_version = nil 28 | update_index = nil 29 | ARGV.each_with_index do |a, i| 30 | if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN 31 | bundler_version = a 32 | end 33 | next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/ 34 | bundler_version = $1 35 | update_index = i 36 | end 37 | bundler_version 38 | end 39 | 40 | def gemfile 41 | gemfile = ENV["BUNDLE_GEMFILE"] 42 | return gemfile if gemfile && !gemfile.empty? 43 | 44 | File.expand_path("../../Gemfile", __FILE__) 45 | end 46 | 47 | def lockfile 48 | lockfile = 49 | case File.basename(gemfile) 50 | when "gems.rb" then gemfile.sub(/\.rb$/, gemfile) 51 | else "#{gemfile}.lock" 52 | end 53 | File.expand_path(lockfile) 54 | end 55 | 56 | def lockfile_version 57 | return unless File.file?(lockfile) 58 | lockfile_contents = File.read(lockfile) 59 | return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/ 60 | Regexp.last_match(1) 61 | end 62 | 63 | def bundler_requirement 64 | @bundler_requirement ||= 65 | env_var_version || cli_arg_version || 66 | bundler_requirement_for(lockfile_version) 67 | end 68 | 69 | def bundler_requirement_for(version) 70 | return "#{Gem::Requirement.default}.a" unless version 71 | 72 | bundler_gem_version = Gem::Version.new(version) 73 | 74 | requirement = bundler_gem_version.approximate_recommendation 75 | 76 | return requirement unless Gem::Version.new(Gem::VERSION) < Gem::Version.new("2.7.0") 77 | 78 | requirement += ".a" if bundler_gem_version.prerelease? 79 | 80 | requirement 81 | end 82 | 83 | def load_bundler! 84 | ENV["BUNDLE_GEMFILE"] ||= gemfile 85 | 86 | activate_bundler 87 | end 88 | 89 | def activate_bundler 90 | gem_error = activation_error_handling do 91 | gem "bundler", bundler_requirement 92 | end 93 | return if gem_error.nil? 94 | require_error = activation_error_handling do 95 | require "bundler/version" 96 | end 97 | return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION)) 98 | warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`" 99 | exit 42 100 | end 101 | 102 | def activation_error_handling 103 | yield 104 | nil 105 | rescue StandardError, LoadError => e 106 | e 107 | end 108 | end 109 | 110 | m.load_bundler! 111 | 112 | if m.invoked_as_script? 113 | load Gem.bin_path("bundler", "bundle") 114 | end 115 | -------------------------------------------------------------------------------- /lib/nordigen-ruby.rb: -------------------------------------------------------------------------------- 1 | require "faraday" 2 | 3 | require_relative "nordigen_ruby/api/institutions" 4 | require_relative "nordigen_ruby/api/agreements" 5 | require_relative "nordigen_ruby/api/requisitions" 6 | require_relative "nordigen_ruby/api/account" 7 | 8 | module Nordigen 9 | class NordigenClient 10 | 11 | BASE_URL = "https://bankaccountdata.gocardless.com/api/v2/" 12 | 13 | @@headers = { 14 | "accept" => "application/json", 15 | "Content-Type" => "application/json", 16 | "User-Agent" => "Nordigen-Ruby-v2" 17 | } 18 | 19 | attr_reader :secret_id, :secret_key, :institution, :agreement, :requisition 20 | 21 | def initialize(secret_id:, secret_key:) 22 | @secret_id = secret_id 23 | @secret_key = secret_key 24 | @institution = InstitutionsApi.new(client=self) 25 | @agreement = AgreementsApi.new(client=self) 26 | @requisition = RequisitionsApi.new(client=self) 27 | end 28 | 29 | def request 30 | # HTTP client request 31 | @request ||= Faraday.new do |conn| 32 | conn.url_prefix = BASE_URL 33 | conn.headers = @@headers 34 | conn.request :json 35 | conn.response :json 36 | end 37 | end 38 | 39 | def set_token(access_token) 40 | # Use existing token 41 | @@headers["Authorization"] = "Bearer #{access_token}" 42 | end 43 | 44 | def get_token 45 | # Get token 46 | return request.headers["Authorization"] 47 | end 48 | 49 | def generate_token 50 | # Generate new access & refresh token 51 | payload = { 52 | "secret_key": @secret_key, 53 | "secret_id": @secret_id 54 | } 55 | response = self.request.post("token/new/", payload) 56 | if !response.success? 57 | raise Exception.new response.body 58 | end 59 | 60 | @@headers["Authorization"] = "Bearer #{response.body['access']}" 61 | request.headers = @@headers 62 | return response.body 63 | end 64 | 65 | def exchange_token(refresh_token) 66 | # Exchange refresh token for access token 67 | payload = {"refresh": refresh_token} 68 | response = self.request.post("token/refresh/", payload).body 69 | @@headers["Authorization"] = "Bearer #{response['access']}" 70 | request.headers = @@headers 71 | return response 72 | end 73 | 74 | 75 | def account(account_id) 76 | # Create Account instance 77 | return AccountApi.new(client: self, account_id: account_id) 78 | end 79 | 80 | def init_session( 81 | redirect_url:, 82 | institution_id:, 83 | reference_id:, 84 | max_historical_days: 90, 85 | access_valid_for_days: 90, 86 | user_language: "en", 87 | account_selection: false, 88 | redirect_immediate: false, 89 | ssn: nil 90 | ) 91 | # Factory method that creates authorization in a specific institution 92 | # and are responsible for the following steps: 93 | # * Creates agreement 94 | # * Creates requisiton 95 | 96 | # Create agreement 97 | new_agreement = @agreement.create_agreement( 98 | institution_id: institution_id, 99 | max_historical_days: max_historical_days, 100 | access_valid_for_days: access_valid_for_days 101 | ) 102 | 103 | # Create requisition 104 | new_requsition = @requisition.create_requisition( 105 | redirect_url: redirect_url, 106 | reference: reference_id, 107 | institution_id: institution_id, 108 | user_language: user_language, 109 | account_selection: account_selection, 110 | redirect_immediate: redirect_immediate, 111 | agreement: new_agreement["id"], 112 | ssn: ssn 113 | ) 114 | 115 | return new_requsition 116 | end 117 | 118 | end 119 | end 120 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nordigen Ruby Library 2 | 3 | ### ⚠️ Notice 4 | Please be advised that the Bank Account Data libraries are no longer actively updated or maintained. While these libraries may still function, GoCardless will not provide further updates, bug fixes, or support for them. 5 | # 6 | 7 | This is official Ruby client library for [GoCardless Bank Account Data](https://gocardless.com/bank-account-data/). 8 | 9 | For a full list of endpoints and arguments, see the [docs](https://developer.gocardless.com/bank-account-data/quick-start-guide). 10 | 11 | Before starting to use API you will need to create a new secret and get your `SECRET_ID` and `SECRET_KEY` from the [GoCardless Bank Account Data Portal](https://bankaccountdata.gocardless.com/user-secrets/). 12 | 13 | ## Requirements 14 | 15 | * Ruby 2.6+ 16 | 17 | 18 | ## Installation 19 | 20 | 21 | Install library 22 | 23 | ``` 24 | gem install nordigen-ruby 25 | ``` 26 | 27 | ## Example application 28 | 29 | Example code can be found in `main.rb` file and Ruby on Rails example application can be found in `example` directory 30 | 31 | ## Quickstart 32 | 33 | 34 | ```ruby 35 | require 'securerandom' 36 | require 'nordigen-ruby' 37 | 38 | # Get secret_id and secret_key from bankaccountdata.gocardless.com/user-secrets/ portal and pass to NordigenClient or load from .env file 39 | client = Nordigen::NordigenClient.new( 40 | secret_id: "SECRET_ID", 41 | secret_key: "SECRET_KEY" 42 | ) 43 | 44 | # Generate new access token. Token is valid for 24 hours 45 | token_data = client.generate_token() 46 | 47 | # Use existing token 48 | client.set_token("YOUR_TOKEN") 49 | 50 | # Get access and refresh token 51 | # Note: access_token is automatically injected to other requests after you successfully obtain it 52 | access_token = token_data["access"] 53 | refresh_token = token_data["refresh"] 54 | 55 | # Exchange refresh token. Refresh token is valid for 30 days 56 | refresh_token = client.exchange_token(refresh_token) 57 | 58 | # Get all institution by providing country code in ISO 3166 format 59 | institutions = client.institution.get_institutions("LV") 60 | 61 | # Institution id can be gathered from get_institutions response. 62 | # Example Revolut ID 63 | id = "REVOLUT_REVOGB21" 64 | 65 | # Initialize bank authorization session 66 | # Returns requisition_id and link to initiate authorization with a bank 67 | init = client.init_session( 68 | # redirect url after successful authentication 69 | redirect_url: "https://gocardless.com", 70 | # institution id 71 | institution_id: id, 72 | # a unique user ID of someone who's using your services, usually it's a UUID 73 | reference_id: SecureRandom.uuid, 74 | # A two-letter country code (ISO 639-1) 75 | user_language: "en", 76 | # option to enable account selection view for the end user 77 | account_selection: true 78 | ) 79 | 80 | link = init["link"] # bank authorization link 81 | requisition_id = init["id"] # requisition id that is needed to get an account_id 82 | puts link 83 | ``` 84 | 85 | After successful authorization with a bank you can fetch your data (details, balances, transactions) 86 | 87 | 88 | ## Fetching account metadata, balances, details and transactions 89 | 90 | ```ruby 91 | 92 | # Get account id after you have completed authorization with a bank. 93 | requisition_data = client.requisition.get_requisition_by_id(requisition_id) 94 | # Get account id from list 95 | account_id = requisition_data["accounts"][0] 96 | 97 | # Instantiate account object 98 | account = client.account(account_id) 99 | 100 | # Fetch account metadata 101 | meta_data = account.get_metadata() 102 | # Fetch details 103 | details = account.get_details() 104 | # Fetch balances 105 | balances = account.get_balances() 106 | # Fetch transactions 107 | transactions = account.get_transactions() 108 | # Fetch premium transactions 109 | transactions = account.get_premium_transactions(date_from: "2021-12-01", date_to: "2022-01-30", country: "LV") 110 | # Filter transactions by specific date range 111 | transactions = account.get_transactions(date_from: "2021-12-01", date_to: "2022-01-30") 112 | ``` 113 | 114 | ## Development 115 | 116 | Run all tests in a directory 117 | ```bash 118 | bundle exec rake test 119 | ``` 120 | 121 | ## Support 122 | 123 | For any inquiries please contact support at [bank-account-data-support@gocardless.com](bank-account-data-support@gocardless.com) or create an issue in repository. 124 | -------------------------------------------------------------------------------- /example/config/environments/production.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # Code is not reloaded between requests. 7 | config.cache_classes = true 8 | 9 | # Eager load code on boot. This eager loads most of Rails and 10 | # your application in memory, allowing both threaded web servers 11 | # and those relying on copy on write to perform better. 12 | # Rake tasks automatically ignore this option for performance. 13 | config.eager_load = true 14 | 15 | # Full error reports are disabled and caching is turned on. 16 | config.consider_all_requests_local = false 17 | config.action_controller.perform_caching = true 18 | 19 | # Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"] 20 | # or in config/master.key. This key is used to decrypt credentials (and other encrypted files). 21 | # config.require_master_key = true 22 | 23 | # Disable serving static files from the `/public` folder by default since 24 | # Apache or NGINX already handles this. 25 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? 26 | 27 | # Compress CSS using a preprocessor. 28 | # config.assets.css_compressor = :sass 29 | 30 | # Do not fallback to assets pipeline if a precompiled asset is missed. 31 | config.assets.compile = false 32 | 33 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 34 | # config.asset_host = 'http://assets.example.com' 35 | 36 | # Specifies the header that your server uses for sending files. 37 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 38 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 39 | 40 | # Store uploaded files on the local file system (see config/storage.yml for options). 41 | config.active_storage.service = :local 42 | 43 | # Mount Action Cable outside main process or domain. 44 | # config.action_cable.mount_path = nil 45 | # config.action_cable.url = 'wss://example.com/cable' 46 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] 47 | 48 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 49 | # config.force_ssl = true 50 | 51 | # Include generic and useful information about system operation, but avoid logging too much 52 | # information to avoid inadvertent exposure of personally identifiable information (PII). 53 | config.log_level = :info 54 | 55 | # Prepend all log lines with the following tags. 56 | config.log_tags = [ :request_id ] 57 | 58 | # Use a different cache store in production. 59 | # config.cache_store = :mem_cache_store 60 | 61 | # Use a real queuing backend for Active Job (and separate queues per environment). 62 | # config.active_job.queue_adapter = :resque 63 | # config.active_job.queue_name_prefix = "app_production" 64 | 65 | config.action_mailer.perform_caching = false 66 | 67 | # Ignore bad email addresses and do not raise email delivery errors. 68 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 69 | # config.action_mailer.raise_delivery_errors = false 70 | 71 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 72 | # the I18n.default_locale when a translation cannot be found). 73 | config.i18n.fallbacks = true 74 | 75 | # Send deprecation notices to registered listeners. 76 | config.active_support.deprecation = :notify 77 | 78 | # Log disallowed deprecations. 79 | config.active_support.disallowed_deprecation = :log 80 | 81 | # Tell Active Support which deprecation messages to disallow. 82 | config.active_support.disallowed_deprecation_warnings = [] 83 | 84 | # Use default logging formatter so that PID and timestamp are not suppressed. 85 | config.log_formatter = ::Logger::Formatter.new 86 | 87 | # Use a different logger for distributed setups. 88 | # require "syslog/logger" 89 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') 90 | 91 | if ENV["RAILS_LOG_TO_STDOUT"].present? 92 | logger = ActiveSupport::Logger.new(STDOUT) 93 | logger.formatter = config.log_formatter 94 | config.logger = ActiveSupport::TaggedLogging.new(logger) 95 | end 96 | 97 | # Do not dump schema after migrations. 98 | config.active_record.dump_schema_after_migration = false 99 | 100 | # Inserts middleware to perform automatic connection switching. 101 | # The `database_selector` hash is used to pass options to the DatabaseSelector 102 | # middleware. The `delay` is used to determine how long to wait after a write 103 | # to send a subsequent read to the primary. 104 | # 105 | # The `database_resolver` class is used by the middleware to determine which 106 | # database is appropriate to use based on the time delay. 107 | # 108 | # The `database_resolver_context` class is used by the middleware to set 109 | # timestamps for the last write to the primary. The resolver uses the context 110 | # class timestamps to determine how long to wait before reading from the 111 | # replica. 112 | # 113 | # By default Rails will store a last write timestamp in the session. The 114 | # DatabaseSelector middleware is designed as such you can define your own 115 | # strategy for connection switching and pass that into the middleware through 116 | # these configuration options. 117 | # config.active_record.database_selector = { delay: 2.seconds } 118 | # config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver 119 | # config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session 120 | end 121 | -------------------------------------------------------------------------------- /example/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actioncable (6.1.7.4) 5 | actionpack (= 6.1.7.4) 6 | activesupport (= 6.1.7.4) 7 | nio4r (~> 2.0) 8 | websocket-driver (>= 0.6.1) 9 | actionmailbox (6.1.7.4) 10 | actionpack (= 6.1.7.4) 11 | activejob (= 6.1.7.4) 12 | activerecord (= 6.1.7.4) 13 | activestorage (= 6.1.7.4) 14 | activesupport (= 6.1.7.4) 15 | mail (>= 2.7.1) 16 | actionmailer (6.1.7.4) 17 | actionpack (= 6.1.7.4) 18 | actionview (= 6.1.7.4) 19 | activejob (= 6.1.7.4) 20 | activesupport (= 6.1.7.4) 21 | mail (~> 2.5, >= 2.5.4) 22 | rails-dom-testing (~> 2.0) 23 | actionpack (6.1.7.4) 24 | actionview (= 6.1.7.4) 25 | activesupport (= 6.1.7.4) 26 | rack (~> 2.0, >= 2.0.9) 27 | rack-test (>= 0.6.3) 28 | rails-dom-testing (~> 2.0) 29 | rails-html-sanitizer (~> 1.0, >= 1.2.0) 30 | actiontext (6.1.7.4) 31 | actionpack (= 6.1.7.4) 32 | activerecord (= 6.1.7.4) 33 | activestorage (= 6.1.7.4) 34 | activesupport (= 6.1.7.4) 35 | nokogiri (>= 1.8.5) 36 | actionview (6.1.7.4) 37 | activesupport (= 6.1.7.4) 38 | builder (~> 3.1) 39 | erubi (~> 1.4) 40 | rails-dom-testing (~> 2.0) 41 | rails-html-sanitizer (~> 1.1, >= 1.2.0) 42 | activejob (6.1.7.4) 43 | activesupport (= 6.1.7.4) 44 | globalid (>= 0.3.6) 45 | activemodel (6.1.7.4) 46 | activesupport (= 6.1.7.4) 47 | activerecord (6.1.7.4) 48 | activemodel (= 6.1.7.4) 49 | activesupport (= 6.1.7.4) 50 | activestorage (6.1.7.4) 51 | actionpack (= 6.1.7.4) 52 | activejob (= 6.1.7.4) 53 | activerecord (= 6.1.7.4) 54 | activesupport (= 6.1.7.4) 55 | marcel (~> 1.0) 56 | mini_mime (>= 1.1.0) 57 | activesupport (6.1.7.4) 58 | concurrent-ruby (~> 1.0, >= 1.0.2) 59 | i18n (>= 1.6, < 2) 60 | minitest (>= 5.1) 61 | tzinfo (~> 2.0) 62 | zeitwerk (~> 2.3) 63 | addressable (2.8.4) 64 | public_suffix (>= 2.0.2, < 6.0) 65 | bindex (0.8.1) 66 | bootsnap (1.16.0) 67 | msgpack (~> 1.2) 68 | builder (3.2.4) 69 | byebug (11.1.3) 70 | capybara (3.39.2) 71 | addressable 72 | matrix 73 | mini_mime (>= 0.1.3) 74 | nokogiri (~> 1.8) 75 | rack (>= 1.6.0) 76 | rack-test (>= 0.6.3) 77 | regexp_parser (>= 1.5, < 3.0) 78 | xpath (~> 3.2) 79 | concurrent-ruby (1.2.2) 80 | crass (1.0.6) 81 | date (3.3.3) 82 | dotenv (2.8.1) 83 | erubi (1.12.0) 84 | faraday (2.7.10) 85 | faraday-net_http (>= 2.0, < 3.1) 86 | ruby2_keywords (>= 0.0.4) 87 | faraday-net_http (3.0.2) 88 | ffi (1.15.5) 89 | globalid (1.1.0) 90 | activesupport (>= 5.0) 91 | i18n (1.14.1) 92 | concurrent-ruby (~> 1.0) 93 | jbuilder (2.11.5) 94 | actionview (>= 5.0.0) 95 | activesupport (>= 5.0.0) 96 | listen (3.8.0) 97 | rb-fsevent (~> 0.10, >= 0.10.3) 98 | rb-inotify (~> 0.9, >= 0.9.10) 99 | loofah (2.21.3) 100 | crass (~> 1.0.2) 101 | nokogiri (>= 1.12.0) 102 | mail (2.8.1) 103 | mini_mime (>= 0.1.1) 104 | net-imap 105 | net-pop 106 | net-smtp 107 | marcel (1.0.2) 108 | matrix (0.4.2) 109 | method_source (1.0.0) 110 | mini_mime (1.1.2) 111 | minitest (5.18.1) 112 | msgpack (1.7.1) 113 | net-imap (0.3.6) 114 | date 115 | net-protocol 116 | net-pop (0.1.2) 117 | net-protocol 118 | net-protocol (0.2.1) 119 | timeout 120 | net-smtp (0.3.3) 121 | net-protocol 122 | nio4r (2.5.9) 123 | nokogiri (1.15.3-arm64-darwin) 124 | racc (~> 1.4) 125 | nokogiri (1.15.3-x86_64-linux) 126 | racc (~> 1.4) 127 | nordigen-ruby (2.1.2) 128 | faraday (~> 2.5) 129 | public_suffix (5.0.3) 130 | puma (5.6.6) 131 | nio4r (~> 2.0) 132 | racc (1.7.1) 133 | rack (2.2.7) 134 | rack-mini-profiler (2.3.4) 135 | rack (>= 1.2.0) 136 | rack-proxy (0.7.6) 137 | rack 138 | rack-test (2.1.0) 139 | rack (>= 1.3) 140 | rails (6.1.7.4) 141 | actioncable (= 6.1.7.4) 142 | actionmailbox (= 6.1.7.4) 143 | actionmailer (= 6.1.7.4) 144 | actionpack (= 6.1.7.4) 145 | actiontext (= 6.1.7.4) 146 | actionview (= 6.1.7.4) 147 | activejob (= 6.1.7.4) 148 | activemodel (= 6.1.7.4) 149 | activerecord (= 6.1.7.4) 150 | activestorage (= 6.1.7.4) 151 | activesupport (= 6.1.7.4) 152 | bundler (>= 1.15.0) 153 | railties (= 6.1.7.4) 154 | sprockets-rails (>= 2.0.0) 155 | rails-dom-testing (2.1.1) 156 | activesupport (>= 5.0.0) 157 | minitest 158 | nokogiri (>= 1.6) 159 | rails-html-sanitizer (1.6.0) 160 | loofah (~> 2.21) 161 | nokogiri (~> 1.14) 162 | railties (6.1.7.4) 163 | actionpack (= 6.1.7.4) 164 | activesupport (= 6.1.7.4) 165 | method_source 166 | rake (>= 12.2) 167 | thor (~> 1.0) 168 | rake (13.0.6) 169 | rb-fsevent (0.11.2) 170 | rb-inotify (0.10.1) 171 | ffi (~> 1.0) 172 | regexp_parser (2.8.1) 173 | rexml (3.2.5) 174 | ruby2_keywords (0.0.5) 175 | rubyzip (2.3.2) 176 | sass-rails (6.0.0) 177 | sassc-rails (~> 2.1, >= 2.1.1) 178 | sassc (2.4.0) 179 | ffi (~> 1.9) 180 | sassc-rails (2.1.2) 181 | railties (>= 4.0.0) 182 | sassc (>= 2.0) 183 | sprockets (> 3.0) 184 | sprockets-rails 185 | tilt 186 | selenium-webdriver (4.10.0) 187 | rexml (~> 3.2, >= 3.2.5) 188 | rubyzip (>= 1.2.2, < 3.0) 189 | websocket (~> 1.0) 190 | semantic_range (3.0.0) 191 | spring (4.1.1) 192 | sprockets (4.2.0) 193 | concurrent-ruby (~> 1.0) 194 | rack (>= 2.2.4, < 4) 195 | sprockets-rails (3.4.2) 196 | actionpack (>= 5.2) 197 | activesupport (>= 5.2) 198 | sprockets (>= 3.0.0) 199 | sqlite3 (1.6.3-arm64-darwin) 200 | sqlite3 (1.6.3-x86_64-linux) 201 | thor (1.2.2) 202 | tilt (2.2.0) 203 | timeout (0.4.0) 204 | turbolinks (5.2.1) 205 | turbolinks-source (~> 5.2) 206 | turbolinks-source (5.2.0) 207 | tzinfo (2.0.6) 208 | concurrent-ruby (~> 1.0) 209 | web-console (4.2.0) 210 | actionview (>= 6.0.0) 211 | activemodel (>= 6.0.0) 212 | bindex (>= 0.4.0) 213 | railties (>= 6.0.0) 214 | webdrivers (5.2.0) 215 | nokogiri (~> 1.6) 216 | rubyzip (>= 1.3.0) 217 | selenium-webdriver (~> 4.0) 218 | webpacker (5.4.4) 219 | activesupport (>= 5.2) 220 | rack-proxy (>= 0.6.1) 221 | railties (>= 5.2) 222 | semantic_range (>= 2.3.0) 223 | websocket (1.2.9) 224 | websocket-driver (0.7.5) 225 | websocket-extensions (>= 0.1.0) 226 | websocket-extensions (0.1.5) 227 | xpath (3.2.0) 228 | nokogiri (~> 1.8) 229 | zeitwerk (2.6.8) 230 | 231 | PLATFORMS 232 | arm64-darwin-22 233 | x86_64-linux 234 | 235 | DEPENDENCIES 236 | bootsnap (>= 1.4.4) 237 | byebug 238 | capybara (>= 3.26) 239 | dotenv 240 | jbuilder (~> 2.7) 241 | listen (~> 3.3) 242 | nordigen-ruby (~> 2.1.2) 243 | puma (~> 5.0) 244 | rack-mini-profiler (~> 2.0) 245 | rails (~> 6.1.4, >= 6.1.4.1) 246 | sass-rails (>= 6) 247 | selenium-webdriver 248 | spring 249 | sqlite3 (~> 1.4) 250 | turbolinks (~> 5) 251 | tzinfo-data 252 | web-console (>= 4.1.0) 253 | webdrivers 254 | webpacker (~> 5.0) 255 | 256 | RUBY VERSION 257 | ruby 3.0.1p64 258 | 259 | BUNDLED WITH 260 | 2.4.16 261 | --------------------------------------------------------------------------------