├── 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 |
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 |
--------------------------------------------------------------------------------