12 |
13 | Features
14 | ------------
15 |
16 | * **Clean, intuitive design** — With Slate, the description of your API is on the left side of your documentation, and all the code examples are on the right side. Inspired by [Stripe's](https://stripe.com/docs/api) and [PayPal's](https://developer.paypal.com/webapps/developer/docs/api/) API docs. Slate is responsive, so it looks great on tablets, phones, and even in print.
17 |
18 | * **Everything on a single page** — Gone are the days when your users had to search through a million pages to find what they wanted. Slate puts the entire documentation on a single page. We haven't sacrificed linkability, though. As you scroll, your browser's hash will update to the nearest header, so linking to a particular point in the documentation is still natural and easy.
19 |
20 | * **Slate is just Markdown** — When you write docs with Slate, you're just writing Markdown, which makes it simple to edit and understand. Everything is written in Markdown — even the code samples are just Markdown code blocks.
21 |
22 | * **Write code samples in multiple languages** — If your API has bindings in multiple programming languages, you can easily put in tabs to switch between them. In your document, you'll distinguish different languages by specifying the language name at the top of each code block, just like with GitHub Flavored Markdown.
23 |
24 | * **Out-of-the-box syntax highlighting** for [over 100 languages](https://github.com/jneen/rouge/wiki/List-of-supported-languages-and-lexers), no configuration required.
25 |
26 | * **Automatic, smoothly scrolling table of contents** on the far left of the page. As you scroll, it displays your current position in the document. It's fast, too. We're using Slate at TripIt to build documentation for our new API, where our table of contents has over 180 entries. We've made sure that the performance remains excellent, even for larger documents.
27 |
28 | * **Let your users update your documentation for you** — By default, your Slate-generated documentation is hosted in a public GitHub repository. Not only does this mean you get free hosting for your docs with GitHub Pages, but it also makes it simple for other developers to make pull requests to your docs if they find typos or other problems. Of course, if you don't want to use GitHub, you're also welcome to host your docs elsewhere.
29 |
30 | * **RTL Support** Full right-to-left layout for RTL languages such as Arabic, Persian (Farsi), Hebrew etc.
31 |
32 | Getting started with Slate is super easy! Simply fork this repository and follow the instructions below. Or, if you'd like to check out what Slate is capable of, take a look at the [sample docs](http://lord.github.io/slate).
33 |
34 | Getting Started with Slate
35 | ------------------------------
36 |
37 | ### Prerequisites
38 |
39 | You're going to need:
40 |
41 | - **Linux or macOS** — Windows may work, but is unsupported.
42 | - **Ruby, version 2.3.1 or newer**
43 | - **Bundler** — If Ruby is already installed, but the `bundle` command doesn't work, just run `gem install bundler` in a terminal.
44 |
45 | ### Getting Set Up
46 |
47 | 1. Fork this repository on GitHub.
48 | 2. Clone *your forked repository* (not our original one) to your hard drive with `git clone https://github.com/YOURUSERNAME/slate.git`
49 | 3. `cd slate`
50 | 4. Initialize and start Slate. You can either do this locally, or with Vagrant:
51 |
52 | ```shell
53 | # either run this to run locally
54 | bundle install
55 | bundle exec middleman server
56 |
57 | # OR run this to run with vagrant
58 | vagrant up
59 | ```
60 |
61 | You can now see the docs at http://localhost:4567. Whoa! That was fast!
62 |
63 | Now that Slate is all set up on your machine, you'll probably want to learn more about [editing Slate markdown](https://github.com/lord/slate/wiki/Markdown-Syntax), or [how to publish your docs](https://github.com/lord/slate/wiki/Deploying-Slate).
64 |
65 | If you'd prefer to use Docker, instructions are available [in the wiki](https://github.com/lord/slate/wiki/Docker).
66 |
67 | ### Note on JavaScript Runtime
68 |
69 | For those who don't have JavaScript runtime or are experiencing JavaScript runtime issues with ExecJS, it is recommended to add the [rubyracer gem](https://github.com/cowboyd/therubyracer) to your gemfile and run `bundle` again.
70 |
71 | Companies Using Slate
72 | ---------------------------------
73 |
74 | * [NASA](https://api.nasa.gov)
75 | * [Sony](http://developers.cimediacloud.com)
76 | * [Best Buy](https://bestbuyapis.github.io/api-documentation/)
77 | * [Travis-CI](https://docs.travis-ci.com/api/)
78 | * [Greenhouse](https://developers.greenhouse.io/harvest.html)
79 | * [Woocommerce](http://woocommerce.github.io/woocommerce-rest-api-docs/)
80 | * [Dwolla](https://docs.dwolla.com/)
81 | * [Clearbit](https://clearbit.com/docs)
82 | * [Coinbase](https://developers.coinbase.com/api)
83 | * [Parrot Drones](http://developer.parrot.com/docs/bebop/)
84 | * [Scale](https://docs.scaleapi.com/)
85 |
86 | You can view more in [the list on the wiki](https://github.com/lord/slate/wiki/Slate-in-the-Wild).
87 |
88 | Questions? Need Help? Found a bug?
89 | --------------------
90 |
91 | If you've got questions about setup, deploying, special feature implementation in your fork, or just want to chat with the developer, please feel free to [start a thread in our Spectrum community](https://spectrum.chat/slate)!
92 |
93 | Found a bug with upstream Slate? Go ahead and [submit an issue](https://github.com/lord/slate/issues). And, of course, feel free to submit pull requests with bug fixes or changes to the `dev` branch.
94 |
95 | Contributors
96 | --------------------
97 |
98 | Slate was built by [Robert Lord](https://lord.io) while interning at [TripIt](https://www.tripit.com/).
99 |
100 | Thanks to the following people who have submitted major pull requests:
101 |
102 | - [@chrissrogers](https://github.com/chrissrogers)
103 | - [@bootstraponline](https://github.com/bootstraponline)
104 | - [@realityking](https://github.com/realityking)
105 | - [@cvkef](https://github.com/cvkef)
106 |
107 | Also, thanks to [Sauce Labs](http://saucelabs.com) for sponsoring the development of the responsive styles.
108 |
109 | Special Thanks
110 | --------------------
111 | - [Middleman](https://github.com/middleman/middleman)
112 | - [jquery.tocify.js](https://github.com/gfranko/jquery.tocify.js)
113 | - [middleman-syntax](https://github.com/middleman/middleman-syntax)
114 | - [middleman-gh-pages](https://github.com/edgecase/middleman-gh-pages)
115 | - [Font Awesome](http://fortawesome.github.io/Font-Awesome/)
116 |
--------------------------------------------------------------------------------
/slate/Vagrantfile:
--------------------------------------------------------------------------------
1 | Vagrant.configure(2) do |config|
2 | config.vm.box = "ubuntu/trusty64"
3 | config.vm.network :forwarded_port, guest: 4567, host: 4567
4 | config.vm.provider "virtualbox" do |vb|
5 | vb.memory = "2048"
6 | end
7 |
8 | config.vm.provision "bootstrap",
9 | type: "shell",
10 | inline: <<-SHELL
11 | sudo apt-add-repository ppa:brightbox/ruby-ng
12 | sudo apt-get update
13 | sudo apt-get install -yq ruby2.4 ruby2.4-dev
14 | sudo apt-get install -yq pkg-config build-essential nodejs git libxml2-dev libxslt-dev
15 | sudo apt-get autoremove -yq
16 | gem2.4 install --no-ri --no-rdoc bundler
17 | SHELL
18 |
19 | # add the local user git config to the vm
20 | config.vm.provision "file", source: "~/.gitconfig", destination: ".gitconfig"
21 |
22 | config.vm.provision "install",
23 | type: "shell",
24 | privileged: false,
25 | inline: <<-SHELL
26 | echo "=============================================="
27 | echo "Installing app dependencies"
28 | cd /vagrant
29 | bundle config build.nokogiri --use-system-libraries
30 | bundle install
31 | SHELL
32 |
33 | config.vm.provision "run",
34 | type: "shell",
35 | privileged: false,
36 | run: "always",
37 | inline: <<-SHELL
38 | echo "=============================================="
39 | echo "Starting up middleman at http://localhost:4567"
40 | echo "If it does not come up, check the ~/middleman.log file for any error messages"
41 | cd /vagrant
42 | bundle exec middleman server --watcher-force-polling --watcher-latency=1 &> ~/middleman.log &
43 | SHELL
44 | end
45 |
--------------------------------------------------------------------------------
/slate/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | bundle exec middleman build --clean
3 |
--------------------------------------------------------------------------------
/slate/config.rb:
--------------------------------------------------------------------------------
1 | # Unique header generation
2 | require './lib/unique_head.rb'
3 |
4 | # Markdown
5 | set :markdown_engine, :redcarpet
6 | set :markdown,
7 | fenced_code_blocks: true,
8 | smartypants: true,
9 | disable_indented_code_blocks: true,
10 | prettify: true,
11 | strikethrough: true,
12 | tables: true,
13 | with_toc_data: true,
14 | no_intra_emphasis: true,
15 | renderer: UniqueHeadCounter
16 |
17 | # Assets
18 | set :css_dir, 'stylesheets'
19 | set :js_dir, 'javascripts'
20 | set :images_dir, 'images'
21 | set :fonts_dir, 'fonts'
22 | set :build_dir, '../docs'
23 |
24 | # Activate the syntax highlighter
25 | activate :syntax
26 | ready do
27 | require './lib/multilang.rb'
28 | end
29 |
30 | activate :sprockets
31 |
32 | activate :autoprefixer do |config|
33 | config.browsers = ['last 2 version', 'Firefox ESR']
34 | config.cascade = false
35 | config.inline = true
36 | end
37 |
38 | # Github pages require relative links
39 | activate :relative_assets
40 | set :relative_links, true
41 |
42 | # Build Configuration
43 | configure :build do
44 | # If you're having trouble with Middleman hanging, commenting
45 | # out the following two lines has been known to help
46 | activate :minify_css
47 | activate :minify_javascript
48 | # activate :relative_assets
49 | # activate :asset_hash
50 | # activate :gzip
51 | end
52 |
53 | # Deploy Configuration
54 | # If you want Middleman to listen on a different port, you can set that below
55 | set :port, 4567
56 | activate :livereload
57 |
58 | helpers do
59 | require './lib/toc_data.rb'
60 | end
61 |
--------------------------------------------------------------------------------
/slate/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -o errexit #abort if any command fails
3 | me=$(basename "$0")
4 |
5 | help_message="\
6 | Usage: $me [-c FILE] []
7 | Deploy generated files to a git branch.
8 |
9 | Options:
10 |
11 | -h, --help Show this help information.
12 | -v, --verbose Increase verbosity. Useful for debugging.
13 | -e, --allow-empty Allow deployment of an empty directory.
14 | -m, --message MESSAGE Specify the message used when committing on the
15 | deploy branch.
16 | -n, --no-hash Don't append the source commit's hash to the deploy
17 | commit's message.
18 | --source-only Only build but not push
19 | --push-only Only push but not build
20 | "
21 |
22 |
23 | run_build() {
24 | bundle exec middleman build --clean
25 | }
26 |
27 | parse_args() {
28 | # Set args from a local environment file.
29 | if [ -e ".env" ]; then
30 | source .env
31 | fi
32 |
33 | # Parse arg flags
34 | # If something is exposed as an environment variable, set/overwrite it
35 | # here. Otherwise, set/overwrite the internal variable instead.
36 | while : ; do
37 | if [[ $1 = "-h" || $1 = "--help" ]]; then
38 | echo "$help_message"
39 | return 0
40 | elif [[ $1 = "-v" || $1 = "--verbose" ]]; then
41 | verbose=true
42 | shift
43 | elif [[ $1 = "-e" || $1 = "--allow-empty" ]]; then
44 | allow_empty=true
45 | shift
46 | elif [[ ( $1 = "-m" || $1 = "--message" ) && -n $2 ]]; then
47 | commit_message=$2
48 | shift 2
49 | elif [[ $1 = "-n" || $1 = "--no-hash" ]]; then
50 | GIT_DEPLOY_APPEND_HASH=false
51 | shift
52 | else
53 | break
54 | fi
55 | done
56 |
57 | # Set internal option vars from the environment and arg flags. All internal
58 | # vars should be declared here, with sane defaults if applicable.
59 |
60 | # Source directory & target branch.
61 | deploy_directory=build
62 | deploy_branch=gh-pages
63 |
64 | #if no user identity is already set in the current git environment, use this:
65 | default_username=${GIT_DEPLOY_USERNAME:-deploy.sh}
66 | default_email=${GIT_DEPLOY_EMAIL:-}
67 |
68 | #repository to deploy to. must be readable and writable.
69 | repo=origin
70 |
71 | #append commit hash to the end of message by default
72 | append_hash=${GIT_DEPLOY_APPEND_HASH:-true}
73 | }
74 |
75 | main() {
76 | parse_args "$@"
77 |
78 | enable_expanded_output
79 |
80 | if ! git diff --exit-code --quiet --cached; then
81 | echo Aborting due to uncommitted changes in the index >&2
82 | return 1
83 | fi
84 |
85 | commit_title=`git log -n 1 --format="%s" HEAD`
86 | commit_hash=` git log -n 1 --format="%H" HEAD`
87 |
88 | #default commit message uses last title if a custom one is not supplied
89 | if [[ -z $commit_message ]]; then
90 | commit_message="publish: $commit_title"
91 | fi
92 |
93 | #append hash to commit message unless no hash flag was found
94 | if [ $append_hash = true ]; then
95 | commit_message="$commit_message"$'\n\n'"generated from commit $commit_hash"
96 | fi
97 |
98 | previous_branch=`git rev-parse --abbrev-ref HEAD`
99 |
100 | if [ ! -d "$deploy_directory" ]; then
101 | echo "Deploy directory '$deploy_directory' does not exist. Aborting." >&2
102 | return 1
103 | fi
104 |
105 | # must use short form of flag in ls for compatibility with macOS and BSD
106 | if [[ -z `ls -A "$deploy_directory" 2> /dev/null` && -z $allow_empty ]]; then
107 | echo "Deploy directory '$deploy_directory' is empty. Aborting. If you're sure you want to deploy an empty tree, use the --allow-empty / -e flag." >&2
108 | return 1
109 | fi
110 |
111 | if git ls-remote --exit-code $repo "refs/heads/$deploy_branch" ; then
112 | # deploy_branch exists in $repo; make sure we have the latest version
113 |
114 | disable_expanded_output
115 | git fetch --force $repo $deploy_branch:$deploy_branch
116 | enable_expanded_output
117 | fi
118 |
119 | # check if deploy_branch exists locally
120 | if git show-ref --verify --quiet "refs/heads/$deploy_branch"
121 | then incremental_deploy
122 | else initial_deploy
123 | fi
124 |
125 | restore_head
126 | }
127 |
128 | initial_deploy() {
129 | git --work-tree "$deploy_directory" checkout --orphan $deploy_branch
130 | git --work-tree "$deploy_directory" add --all
131 | commit+push
132 | }
133 |
134 | incremental_deploy() {
135 | #make deploy_branch the current branch
136 | git symbolic-ref HEAD refs/heads/$deploy_branch
137 | #put the previously committed contents of deploy_branch into the index
138 | git --work-tree "$deploy_directory" reset --mixed --quiet
139 | git --work-tree "$deploy_directory" add --all
140 |
141 | set +o errexit
142 | diff=$(git --work-tree "$deploy_directory" diff --exit-code --quiet HEAD --)$?
143 | set -o errexit
144 | case $diff in
145 | 0) echo No changes to files in $deploy_directory. Skipping commit.;;
146 | 1) commit+push;;
147 | *)
148 | echo git diff exited with code $diff. Aborting. Staying on branch $deploy_branch so you can debug. To switch back to master, use: git symbolic-ref HEAD refs/heads/master && git reset --mixed >&2
149 | return $diff
150 | ;;
151 | esac
152 | }
153 |
154 | commit+push() {
155 | set_user_id
156 | git --work-tree "$deploy_directory" commit -m "$commit_message"
157 |
158 | disable_expanded_output
159 | #--quiet is important here to avoid outputting the repo URL, which may contain a secret token
160 | git push --quiet $repo $deploy_branch
161 | enable_expanded_output
162 | }
163 |
164 | #echo expanded commands as they are executed (for debugging)
165 | enable_expanded_output() {
166 | if [ $verbose ]; then
167 | set -o xtrace
168 | set +o verbose
169 | fi
170 | }
171 |
172 | #this is used to avoid outputting the repo URL, which may contain a secret token
173 | disable_expanded_output() {
174 | if [ $verbose ]; then
175 | set +o xtrace
176 | set -o verbose
177 | fi
178 | }
179 |
180 | set_user_id() {
181 | if [[ -z `git config user.name` ]]; then
182 | git config user.name "$default_username"
183 | fi
184 | if [[ -z `git config user.email` ]]; then
185 | git config user.email "$default_email"
186 | fi
187 | }
188 |
189 | restore_head() {
190 | if [[ $previous_branch = "HEAD" ]]; then
191 | #we weren't on any branch before, so just set HEAD back to the commit it was on
192 | git update-ref --no-deref HEAD $commit_hash $deploy_branch
193 | else
194 | git symbolic-ref HEAD refs/heads/$previous_branch
195 | fi
196 |
197 | git reset --mixed
198 | }
199 |
200 | filter() {
201 | sed -e "s|$repo|\$repo|g"
202 | }
203 |
204 | sanitize() {
205 | "$@" 2> >(filter 1>&2) | filter
206 | }
207 |
208 | if [[ $1 = --source-only ]]; then
209 | run_build
210 | elif [[ $1 = --push-only ]]; then
211 | main "$@"
212 | else
213 | run_build
214 | main "$@"
215 | fi
216 |
--------------------------------------------------------------------------------
/slate/font-selection.json:
--------------------------------------------------------------------------------
1 | {
2 | "IcoMoonType": "selection",
3 | "icons": [
4 | {
5 | "icon": {
6 | "paths": [
7 | "M438.857 73.143q119.429 0 220.286 58.857t159.714 159.714 58.857 220.286-58.857 220.286-159.714 159.714-220.286 58.857-220.286-58.857-159.714-159.714-58.857-220.286 58.857-220.286 159.714-159.714 220.286-58.857zM512 785.714v-108.571q0-8-5.143-13.429t-12.571-5.429h-109.714q-7.429 0-13.143 5.714t-5.714 13.143v108.571q0 7.429 5.714 13.143t13.143 5.714h109.714q7.429 0 12.571-5.429t5.143-13.429zM510.857 589.143l10.286-354.857q0-6.857-5.714-10.286-5.714-4.571-13.714-4.571h-125.714q-8 0-13.714 4.571-5.714 3.429-5.714 10.286l9.714 354.857q0 5.714 5.714 10t13.714 4.286h105.714q8 0 13.429-4.286t6-10z"
8 | ],
9 | "attrs": [],
10 | "isMulticolor": false,
11 | "tags": [
12 | "exclamation-circle"
13 | ],
14 | "defaultCode": 61546,
15 | "grid": 14
16 | },
17 | "attrs": [],
18 | "properties": {
19 | "id": 100,
20 | "order": 4,
21 | "prevSize": 28,
22 | "code": 58880,
23 | "name": "exclamation-sign",
24 | "ligatures": ""
25 | },
26 | "setIdx": 0,
27 | "iconIdx": 0
28 | },
29 | {
30 | "icon": {
31 | "paths": [
32 | "M585.143 786.286v-91.429q0-8-5.143-13.143t-13.143-5.143h-54.857v-292.571q0-8-5.143-13.143t-13.143-5.143h-182.857q-8 0-13.143 5.143t-5.143 13.143v91.429q0 8 5.143 13.143t13.143 5.143h54.857v182.857h-54.857q-8 0-13.143 5.143t-5.143 13.143v91.429q0 8 5.143 13.143t13.143 5.143h256q8 0 13.143-5.143t5.143-13.143zM512 274.286v-91.429q0-8-5.143-13.143t-13.143-5.143h-109.714q-8 0-13.143 5.143t-5.143 13.143v91.429q0 8 5.143 13.143t13.143 5.143h109.714q8 0 13.143-5.143t5.143-13.143zM877.714 512q0 119.429-58.857 220.286t-159.714 159.714-220.286 58.857-220.286-58.857-159.714-159.714-58.857-220.286 58.857-220.286 159.714-159.714 220.286-58.857 220.286 58.857 159.714 159.714 58.857 220.286z"
33 | ],
34 | "attrs": [],
35 | "isMulticolor": false,
36 | "tags": [
37 | "info-circle"
38 | ],
39 | "defaultCode": 61530,
40 | "grid": 14
41 | },
42 | "attrs": [],
43 | "properties": {
44 | "id": 85,
45 | "order": 3,
46 | "name": "info-sign",
47 | "prevSize": 28,
48 | "code": 58882
49 | },
50 | "setIdx": 0,
51 | "iconIdx": 2
52 | },
53 | {
54 | "icon": {
55 | "paths": [
56 | "M733.714 419.429q0-16-10.286-26.286l-52-51.429q-10.857-10.857-25.714-10.857t-25.714 10.857l-233.143 232.571-129.143-129.143q-10.857-10.857-25.714-10.857t-25.714 10.857l-52 51.429q-10.286 10.286-10.286 26.286 0 15.429 10.286 25.714l206.857 206.857q10.857 10.857 25.714 10.857 15.429 0 26.286-10.857l310.286-310.286q10.286-10.286 10.286-25.714zM877.714 512q0 119.429-58.857 220.286t-159.714 159.714-220.286 58.857-220.286-58.857-159.714-159.714-58.857-220.286 58.857-220.286 159.714-159.714 220.286-58.857 220.286 58.857 159.714 159.714 58.857 220.286z"
57 | ],
58 | "attrs": [],
59 | "isMulticolor": false,
60 | "tags": [
61 | "check-circle"
62 | ],
63 | "defaultCode": 61528,
64 | "grid": 14
65 | },
66 | "attrs": [],
67 | "properties": {
68 | "id": 83,
69 | "order": 9,
70 | "prevSize": 28,
71 | "code": 58886,
72 | "name": "ok-sign"
73 | },
74 | "setIdx": 0,
75 | "iconIdx": 6
76 | },
77 | {
78 | "icon": {
79 | "paths": [
80 | "M658.286 475.429q0-105.714-75.143-180.857t-180.857-75.143-180.857 75.143-75.143 180.857 75.143 180.857 180.857 75.143 180.857-75.143 75.143-180.857zM950.857 950.857q0 29.714-21.714 51.429t-51.429 21.714q-30.857 0-51.429-21.714l-196-195.429q-102.286 70.857-228 70.857-81.714 0-156.286-31.714t-128.571-85.714-85.714-128.571-31.714-156.286 31.714-156.286 85.714-128.571 128.571-85.714 156.286-31.714 156.286 31.714 128.571 85.714 85.714 128.571 31.714 156.286q0 125.714-70.857 228l196 196q21.143 21.143 21.143 51.429z"
81 | ],
82 | "width": 951,
83 | "attrs": [],
84 | "isMulticolor": false,
85 | "tags": [
86 | "search"
87 | ],
88 | "defaultCode": 61442,
89 | "grid": 14
90 | },
91 | "attrs": [],
92 | "properties": {
93 | "id": 2,
94 | "order": 1,
95 | "prevSize": 28,
96 | "code": 58887,
97 | "name": "icon-search"
98 | },
99 | "setIdx": 0,
100 | "iconIdx": 7
101 | }
102 | ],
103 | "height": 1024,
104 | "metadata": {
105 | "name": "slate",
106 | "license": "SIL OFL 1.1"
107 | },
108 | "preferences": {
109 | "showGlyphs": true,
110 | "showQuickUse": true,
111 | "showQuickUse2": true,
112 | "showSVGs": true,
113 | "fontPref": {
114 | "prefix": "icon-",
115 | "metadata": {
116 | "fontFamily": "slate",
117 | "majorVersion": 1,
118 | "minorVersion": 0,
119 | "description": "Based on FontAwesome",
120 | "license": "SIL OFL 1.1"
121 | },
122 | "metrics": {
123 | "emSize": 1024,
124 | "baseline": 6.25,
125 | "whitespace": 50
126 | },
127 | "resetPoint": 58880,
128 | "showSelector": false,
129 | "selector": "class",
130 | "classSelector": ".icon",
131 | "showMetrics": false,
132 | "showMetadata": true,
133 | "showVersion": true,
134 | "ie7": false
135 | },
136 | "imagePref": {
137 | "prefix": "icon-",
138 | "png": true,
139 | "useClassSelector": true,
140 | "color": 4473924,
141 | "bgColor": 16777215
142 | },
143 | "historySize": 100,
144 | "showCodes": true,
145 | "gridSize": 16,
146 | "showLiga": false
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/slate/lib/multilang.rb:
--------------------------------------------------------------------------------
1 | module Multilang
2 | def block_code(code, full_lang_name)
3 | if full_lang_name
4 | parts = full_lang_name.split('--')
5 | rouge_lang_name = (parts) ? parts[0] : "" # just parts[0] here causes null ref exception when no language specified
6 | super(code, rouge_lang_name).sub("highlight #{rouge_lang_name}") do |match|
7 | match + " tab-" + full_lang_name
8 | end
9 | else
10 | super(code, full_lang_name)
11 | end
12 | end
13 | end
14 |
15 | require 'middleman-core/renderers/redcarpet'
16 | Middleman::Renderers::MiddlemanRedcarpetHTML.send :include, Multilang
17 |
--------------------------------------------------------------------------------
/slate/lib/nesting_unique_head.rb:
--------------------------------------------------------------------------------
1 | # Nested unique header generation
2 | require 'middleman-core/renderers/redcarpet'
3 |
4 | class NestingUniqueHeadCounter < Middleman::Renderers::MiddlemanRedcarpetHTML
5 | def initialize
6 | super
7 | @@headers_history = {} if !defined?(@@headers_history)
8 | end
9 |
10 | def header(text, header_level)
11 | friendly_text = text.gsub(/<[^>]*>/,"").parameterize
12 | @@headers_history[header_level] = text.parameterize
13 |
14 | if header_level > 1
15 | for i in (header_level - 1).downto(1)
16 | friendly_text.prepend("#{@@headers_history[i]}-") if @@headers_history.key?(i)
17 | end
18 | end
19 |
20 | return "#{text}"
21 | end
22 | end
23 |
--------------------------------------------------------------------------------
/slate/lib/toc_data.rb:
--------------------------------------------------------------------------------
1 | require 'nokogiri'
2 |
3 | def toc_data(page_content)
4 | html_doc = Nokogiri::HTML::DocumentFragment.parse(page_content)
5 |
6 | # get a flat list of headers
7 | headers = []
8 | html_doc.css('h1, h2, h3').each do |header|
9 | headers.push({
10 | id: header.attribute('id').to_s,
11 | content: header.children,
12 | title: header.children.to_s.gsub(/<[^>]*>/, ''),
13 | level: header.name[1].to_i,
14 | children: []
15 | })
16 | end
17 |
18 | [3,2].each do |header_level|
19 | header_to_nest = nil
20 | headers = headers.reject do |header|
21 | if header[:level] == header_level
22 | header_to_nest[:children].push header if header_to_nest
23 | true
24 | else
25 | header_to_nest = header if header[:level] < header_level
26 | false
27 | end
28 | end
29 | end
30 | headers
31 | end
32 |
--------------------------------------------------------------------------------
/slate/lib/unique_head.rb:
--------------------------------------------------------------------------------
1 | # Unique header generation
2 | require 'middleman-core/renderers/redcarpet'
3 | require 'digest'
4 | class UniqueHeadCounter < Middleman::Renderers::MiddlemanRedcarpetHTML
5 | def initialize
6 | super
7 | @head_count = {}
8 | end
9 | def header(text, header_level)
10 | friendly_text = text.gsub(/<[^>]*>/,"").parameterize
11 | if friendly_text.strip.length == 0
12 | # Looks like parameterize removed the whole thing! It removes many unicode
13 | # characters like Chinese and Russian. To get a unique URL, let's just
14 | # URI escape the whole header
15 | friendly_text = Digest::SHA1.hexdigest(text)[0,10]
16 | end
17 | @head_count[friendly_text] ||= 0
18 | @head_count[friendly_text] += 1
19 | if @head_count[friendly_text] > 1
20 | friendly_text += "-#{@head_count[friendly_text]}"
21 | end
22 | return "#{text}"
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/slate/run.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | bundle exec middleman server
3 |
--------------------------------------------------------------------------------
/slate/source/fonts/slate.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConsumerDataStandardsAustralia/infosec/1524fc8a727e64ccc39cb2a26a47ed3d0e132c41/slate/source/fonts/slate.eot
--------------------------------------------------------------------------------
/slate/source/fonts/slate.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
15 |
--------------------------------------------------------------------------------
/slate/source/fonts/slate.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConsumerDataStandardsAustralia/infosec/1524fc8a727e64ccc39cb2a26a47ed3d0e132c41/slate/source/fonts/slate.ttf
--------------------------------------------------------------------------------
/slate/source/fonts/slate.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConsumerDataStandardsAustralia/infosec/1524fc8a727e64ccc39cb2a26a47ed3d0e132c41/slate/source/fonts/slate.woff
--------------------------------------------------------------------------------
/slate/source/fonts/slate.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConsumerDataStandardsAustralia/infosec/1524fc8a727e64ccc39cb2a26a47ed3d0e132c41/slate/source/fonts/slate.woff2
--------------------------------------------------------------------------------
/slate/source/images/clientCredentialsSequence.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConsumerDataStandardsAustralia/infosec/1524fc8a727e64ccc39cb2a26a47ed3d0e132c41/slate/source/images/clientCredentialsSequence.png
--------------------------------------------------------------------------------
/slate/source/images/holderDomain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConsumerDataStandardsAustralia/infosec/1524fc8a727e64ccc39cb2a26a47ed3d0e132c41/slate/source/images/holderDomain.png
--------------------------------------------------------------------------------
/slate/source/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConsumerDataStandardsAustralia/infosec/1524fc8a727e64ccc39cb2a26a47ed3d0e132c41/slate/source/images/logo.png
--------------------------------------------------------------------------------
/slate/source/images/logoSanta.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConsumerDataStandardsAustralia/infosec/1524fc8a727e64ccc39cb2a26a47ed3d0e132c41/slate/source/images/logoSanta.png
--------------------------------------------------------------------------------
/slate/source/images/navbar.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConsumerDataStandardsAustralia/infosec/1524fc8a727e64ccc39cb2a26a47ed3d0e132c41/slate/source/images/navbar.png
--------------------------------------------------------------------------------
/slate/source/images/redirPartA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConsumerDataStandardsAustralia/infosec/1524fc8a727e64ccc39cb2a26a47ed3d0e132c41/slate/source/images/redirPartA.png
--------------------------------------------------------------------------------
/slate/source/images/redirPartB.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConsumerDataStandardsAustralia/infosec/1524fc8a727e64ccc39cb2a26a47ed3d0e132c41/slate/source/images/redirPartB.png
--------------------------------------------------------------------------------
/slate/source/images/redirPartC.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ConsumerDataStandardsAustralia/infosec/1524fc8a727e64ccc39cb2a26a47ed3d0e132c41/slate/source/images/redirPartC.png
--------------------------------------------------------------------------------
/slate/source/index.html.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Consumer Data Right Security Profile
3 |
4 | language_tabs: # must be one of https://git.io/vQNgJ
5 | - http
6 |
7 | toc_footers:
8 | - Consumer Data Standards Home
9 | - CDR InfoSec on GitHub
10 |
11 | search: true
12 | ---
13 |
14 |
20 |
21 | # Introduction
22 |
23 | This Information Security profile has been developed as part of the introduction in Australia of the [Consumer Data Right](https://www.accc.gov.au/focus-areas/consumer-data-right "ACCC Consumer Data Right webpage") legislation to give Australians greater control over their data.
24 |
25 | The Consumer Data Right is intended to apply sector by sector across the whole economy, beginning in the banking, energy and telecommunications sectors. These standards have been developed to facilitate the Consumer Data Right by acting as a specific baseline for implementation.
26 |
27 | These standards are governed by the Consumer Data Standards team inside Data61. Data61 has been appointed as the interim standards body. The work of the team is overseen by Mr. Andrew Stevens as interim Chair, with industry and consumer advice provided by an Advisory Committee. Data61 works closely with the Australian Competition and Consumer Commission (ACCC) as lead regulator of the Consumer Data Right, supported by the Office of the Australian Information Commissioner (OAIC).
28 |
29 |
30 |
37 |
38 | # 1. InfoSec Profile 0.1.1
39 |
40 |
43 |
44 | ## 1.1. History
45 |
46 | | Author | Date | Version | Description |
47 | |-----------------|------------|---------|------------|
48 | | LP | 22/11/2018 | 0.0.1 | Created |
49 | | LP | 30/11/2018 | 0.0.2 | Created |
50 | | LP | 10/12/2018 | 0.0.3 | Created |
51 | | LP | 20/12/2018 | 0.1.0 | Created |
52 | | LP | 07/01/2019 | 0.1.1 | Created |
53 |
54 | The detailed change log for this artifact is available [here](https://github.com/ConsumerDataStandardsAustralia/infosec/blob/master/CHANGELOG.md).
55 |
56 | ## 1.2. Symbols and Abbreviated terms
57 | - **API**: Application Programming Interface
58 | - **CA**: Certificate Authority
59 | - **CDR:** Consumer Data Right
60 | - **CDR-SP**: Consumer Data Right Security Profile
61 | - **CIBA**: Client Initiated Backchannel Authentication
62 | - **CL**: Credential Level
63 | - **DH:** Data Holder
64 | - **DR:** Data Recipient
65 | - **DTA:** Digital Transformation Agency
66 | - **FAPI:** Financial API
67 | - **HoK:** Holder of Key
68 | - **JSON:** The JavaScript Object Notation
69 | - **JWA:** JSON Web Algorithms
70 | - **JWE:** JSON Web Encryption
71 | - **JWK:** JSON Web Key
72 | - **JWKS:** JSON Web Key Set
73 | - **JWS:** JSON Web Signing
74 | - **JWT:** JSON Web Token
75 | - **IP:** Identity Proofing
76 | - **LoA:** Level of Assurance
77 | - **LoAs:** Levels of Assurance
78 | - **MTLS:** Mutual Transport Layer Security
79 | - **OIDC:** Open ID Connect
80 | - **PI:** Personal Information
81 | - **PKI:** Public Key Infrastructure
82 | - **PPID:** Pairwise Pseudonymous Identifier
83 | - **REST:** Representational State Transfer
84 | - **TDIF:** Trusted Digital Identity Framework
85 | - **TLS:** Transport Layer Security
86 | - **VoT:** Vector of Trust
87 |
88 | ## 1.3. Requirements Notation and Conventions
89 | The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://tools.ietf.org/html/rfc2119) **[RFC2119]**.
90 |
91 | # 2. Overview
92 | This artifact details the [Consumer Data Right](https://www.accc.gov.au/focus-areas/consumer-data-right) **[CDR]** Information Security
93 | Profile (CDR-SP). This profile will be built upon the foundations of the
94 | [Financial-grade API Read Write Profile](https://openid.net/specs/openid-financial-api-part-2.html) **[FAPI-RW]**, the [Financial-grade API Client Initiated Backchannel Authentication Profile](https://bitbucket.org/openid/fapi/src/master/Financial_API_WD_CIBA.md?fileviewer=file-view-default) **[FAPI-CIBA]**, and other standards relating to
95 | [Open ID Connect 1.0](http://openid.net/specs/openid-connect-core-1_0.html) **[OIDC]**.
96 |
97 | Whilst this is a technical artifact, it is guided by the core principles that
98 | have to led to the creation of the Consumer Data Right. These are:
99 |
100 | - The CDR should be *consumer focussed*.
101 | - The CDR should encourage *competition*.
102 | - The CDR should create *opportunities*.
103 | - The CDR should be *efficient and fair*.
104 |
105 | # 3. CDR Federation
106 | The CDR Federation will facilitate the secure exchange of consumer data and federation metadata between
107 | multiple system entities which will assume one or more of the following roles:
108 |
109 | - **Data Holder**:
110 | - Multiple Data Holders will be supported.
111 | - **Data Recipient**:
112 | - Multiple Data Recipients will be supported.
113 | - **Registry**:
114 | - It is envisaged that only one registry will be supported and will be
115 | maintained by the Australian Competition and Consumer Commission (ACCC).
116 |
117 | ## 3.1. Data Holder
118 | The Data Holder (DH) is a system entity that authenticates a consumer
119 | (resource owner or user), as part of an authorisation process initiated by a Data
120 | Recipient, and issues an authorisation for that Data Recipient to access the consumer's data via published APIs.
121 |
122 | A Data Holder assumes the role of an **[OIDC]** [OpenID Provider](https://openid.net/specs/openid-connect-core-1_0.html#Overview).
123 |
124 | ## 3.2. Data Recipient
125 | A Data Recipient (DR) is system entity that is authorised by a
126 | Data Holder to access consumer resources (APIs). A Data Recipient MUST capture consumer consent prior to commencing an authorisation process with a Data Holder.
127 |
128 | A Data Recipient MUST be accredited in order to participate in the CDR Federation. Accreditation rules for Data Recipients are beyond the scope of this artifact.
129 |
130 | A Data Recipient assumes the role of an **[OIDC]** [Relying Party (Client)](https://openid.net/specs/openid-connect-core-1_0.html#Overview).
131 |
132 | ## 3.3. Registry
133 |
136 |
137 | The Registry is a central point of discovery for both Data Holders and Data
138 | Recipients. Data Holders and Data Recipients must be created as entities in the Registry in order for them to participate as members of the CDR Federation. The functionality of the Registry will include but will not be limited to:
139 |
140 | - **Management of Identities and Access**: The Registry will allow registered persons, on behalf of Data Holders and Data Recipients, to manage the metadata of their associated organisations and systems.
141 | - **Management of Certificates**: The Registry will facilitate the issuing, management and revocation of digital certificates.
142 | - **Discoverability and Search**: The Registry will expose APIs and GUIs (Web applications) in order to support metadata queries across Registry entities.
143 |
144 | A full description of the Registry is beyond the scope of this document.
145 |
146 | # 4. Authentication Flows
147 | This profile supports the authentication flows specified by [FAPI](https://openid.net/wg/fapi/) **[FAPI]**. These are:
148 |
149 | - The Hybrid Flow outlined at [section 3.3](https://openid.net/specs/openid-connect-core-1_0.html#HybridFlowAuth) of **[OIDC]**.
150 | - This MUST be supported by Data Holders.
151 | - The Client Initiated Backchannel Authentication flow outlined under the [FAPI CIBA profile](https://bitbucket.org/openid/fapi/src/master/Financial_API_WD_CIBA.md?fileviewer=file-view-default) **[FAPI-CIBA]**.
152 | - This MAY be supported by Data Holders.
153 |
154 |
155 | ## 4.1. OIDC Hybrid Flow
156 | The **[OIDC]** Hybrid Flow is a type of redirection flow where the consumers user
157 | agent is redirected from a Data Recipient’s (Relying Party) web site to a Data
158 | Holder’s Authorisation endpoint in the context of an **[OIDC]** authentication
159 | request. The Hybrid flow incorporates aspects of the both the implicit flow and
160 | authorisation code flow detailed under **[OIDC]**.
161 |
162 | Only a `response_type` (see [section 3](https://openid.net/specs/openid-connect-core-1_0.html#Authentication) of **[OIDC]**) of `code id_token` SHALL be allowed.
163 |
164 | The `request_uri` parameter SHALL NOT be supported.
165 |
166 |
167 | ## 4.2. Client-Initiated Backchannel Authentication (CIBA)
168 | Client Initiated Backchannel Authentication (CIBA) enables a Data Recipient (Client) to
169 | initiate the authentication of an end-user at a Data Holder (OpenID Provider) by means of decoupled or out-band
170 | mechanisms **[FAPI-CIBA]**.
171 |
172 | Authorisation server rules for **[FAPI-CIBA]** are covered under [section 5.2.2 of the FAPI CIBA profile](https://bitbucket.org/openid/fapi/src/master/Financial_API_WD_CIBA.md?fileviewer=file-view-default#markdown-header-522-authorization-server).
173 |
174 | Login hints MUST not reveal Personal Information (PI) about the consumer or end-user.
175 |
176 | Client rules for **[FAPI-CIBA]** are outlined under [section 5.2.3 of the FAPI CIBA profile](https://bitbucket.org/openid/fapi/src/master/Financial_API_WD_CIBA.md?fileviewer=file-view-default#markdown-header-523-confidential-client).
177 |
178 |
179 | # 5. Client Authentication
180 | Data Holder's MUST support the `private_key_jwt` Client Authentication method specified at [section 9](https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication) of **[OIDC]**.
181 |
182 | The PKI Mutual TLS OAuth Client Authentication Method SHALL not be supported. However as specified under [section 11.2](#mutual-tls), all back-channel communication between Data Recipient and Data Holder systems MUST incorporate, unless stated otherwise, MTLS as part of the TLS handshake.
183 |
184 | ## 5.1. private\_key\_jwt
185 |
186 |
187 | > Non-Normative Example
188 |
189 | ```
190 | POST /token HTTP/1.1
191 | Host: www.holder.com.au
192 | Content-Type: application/x-www-form-urlencoded
193 |
194 | grant_type=authorization_code&
195 | code=i1WsRn1uB1&
196 | client_id=s6BhdRkqt3&
197 | client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&
198 | client_assertion=eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyNDU2In0.ey ...
199 |
200 | # Decoded client assertion JWT
201 | {
202 | "alg": "PS256",
203 | "typ": "JWT",
204 | "kid": "12456"
205 | }
206 | {
207 | "iss": "12345",
208 | "sub": "12345",
209 | "iat": 1516239022,
210 | "exp": 1516239322,
211 | "aud": "https://www.holder.com.au/token",
212 | "jti": "37747cd1-c105-4569-9f75-4adf28b73e31"
213 | }
214 | ```
215 |
216 | The `private_key_jwt` authentication method is enabled through the delivery of an encoded **[JWT]** signed using the Data Recipient's private key and thus facilitates non-repudiation. The **[JWT]** represents an assertion that MUST include the following claims:
217 |
218 | - `iss`: The client ID of the bearer.
219 | - `sub`: The client ID of the bearer.
220 | - `aud`: The URL of the endpoint being invoked.
221 | - `exp`: A JSON number representing the number of seconds from 1970-01-01T00:00:00Z to the UTC expiry time.
222 | - `jti`: A unique identifier generated by the client for this authentication.
223 |
224 | The following claims MAY be included:
225 |
226 | - `iat`: A JSON number representing the number of seconds from 1970-01-01T00:00:00Z to the UTC issued at time.
227 |
228 | When invoking a protected endpoint, the aforementioned assertion MUST be sent with the `POST` method and MUST include the following parameters:
229 |
230 | - `grant_type`: This parameter MUST only be included when invoking the Token Endpoint and MUST be set to `authorisation_code` or `client_credentials`.
231 | - `code`: This parameter MUST only be included when invoking the Token Endpoint after utilising the [Hybrid Authentication flow](#hybrid-flow). This is the value of the code parameter returned in the authorisation response.
232 | - `client_id`: The ID of the calling Client.
233 | - `client_assertion_type`: This MUST be set to `urn:ietf:params:oauth:client-assertion-type:jwt-bearer`.
234 | - `client_assertion`: The encoded assertion JWT.
235 |
236 | # 6. OIDC Client Types
237 | Only Confidential Clients SHALL be supported under this profile. Therefore, Public clients SHALL NOT be supported.
238 |
239 | # 7. Tokens
240 |
241 | ## 7.1. ID Token
242 |
243 | > Non-Normative Example - acr
244 |
245 | ```
246 | {
247 | "iss": "https://www.holder.com.au",
248 | "sub": "a9ebbef6-1f0b-44eb-96cf-0c5b51b37ab2",
249 | "aud": "12345",
250 | "nonce": "n-0S6_WzA2Mj",
251 | "exp": 1311281970,
252 | "iat": 1311280970,
253 | "nbf": 1311280970,
254 | "auth_time": 1311280969,
255 | "acr": "urn:cds.au:cdr:3"
256 | }
257 | ```
258 |
259 | > Non-Normative Example - vot
260 |
261 | ```
262 | {
263 | "iss": "https://www.holder.com.au",
264 | "sub": "a9ebbef6-1f0b-44eb-96cf-0c5b51b37ab2",
265 | "aud": "12345",
266 | "nonce": "n-0S6_WzA2Mj",
267 | "exp": 1311281970,
268 | "iat": 1311280970,
269 | "auth_time": 1311280969,
270 | "vot": "CL2",
271 | "vtm": "https://vector.com/trustmark".
272 | }
273 | ```
274 |
275 | ID Tokens are specified in [section 2](https://openid.net/specs/openid-connect-core-1_0.html#IDToken) of the **[OIDC]** standard. In accordance with **[FAPI-RW]**, ID Tokens must be signed and encrypted when returned
276 | to a Data Recipient from both the Authorisation
277 | Endpoint and Token Endpoint.
278 |
279 | As described under [section 5.2.2](https://openid.net/specs/openid-financial-api-part-2.html#authorization-server) of the **[FAPI-RW]** profile, ID Tokens MUST include the following claims (in addition to the mandatory claims specified in [section 2](https://openid.net/specs/openid-connect-core-1_0.html#IDToken) of the **[OIDC]** standard) as part of [Hybrid Flow authentication](#hybrid):
280 |
281 | - `nonce`: String value used to associate a Client session with an ID Token.
282 | - `s_hash`: Hash of the state value.
283 | - `c_hash`: Hash of the authorisation_code value.
284 |
285 | ID Tokens MUST be signed by Data Holders as specified in [section 8.6](https://openid.net/specs/openid-financial-api-part-2.html#jws-algorithm-considerations) of **[FAPI-RW]**.
286 |
287 | The ID Token returned from the Authorisation Endpoint MUST NOT contain any Personal Information (PI) claims.
288 |
289 | An ID Token MUST not contain both a `vot` claim (see [Vectors of Trust](#vector-loas)) and an `acr` claim .
290 |
291 | If the ID Token contains a `vot` claim, it MUST also contain a `vtm` claim:
292 |
293 | - `vtm`: The trustmark URI as specified in [section 5](https://tools.ietf.org/html/draft-richer-vectors-of-trust-15#section-5) of **[VOT]** .
294 |
295 | ### 7.1.1. Hashing value for state and authorisation code
296 | The `c_hash` value MUST be generated according to [section 3.3.2.11](https://openid.net/specs/openid-connect-core-1_0.html#HybridIDToken) of **[OIDC]**.
297 |
298 | The `s_hash` value MUST be generated according to [section 5.1](https://openid.net/specs/openid-financial-api-part-2.html#introduction) of **[FAPI-RW]**.
299 |
300 | ## 7.2. Access Token
301 | Access Tokens MUST be used as specified in [section 10.3] (https://tools.ietf.org/html/rfc6749#section-10.3) of **[OAUTH2]**. An
302 | Access Token MUST expire `n` minutes after it is issued by the Data Holder where `n` is determined by **[CDR]** rules.
303 |
304 | The process for refreshing an Access Token is described in [section 12.1](https://openid.net/specs/openid-connect-core-1_0.html#RefreshingAccessToken) of **[OIDC]**.
305 |
306 | ## 7.3. Refresh Token
307 | Refresh Tokens MUST be supported by Data Holders. The usage of Refresh Tokens is specified in [section 12](https://openid.net/specs/openid-connect-core-1_0.html#RefreshTokens) of **[OIDC]**.
308 | A Refresh Token MUST expire `n` days after it is issued where `n` is determined by **[CDR]** rules.
309 |
310 | # 8. Scopes and Claims
311 | Industry-specific scopes (for example, `bank_account`) will not be referenced in
312 | this profile.
313 |
314 | ## 8.1. Scopes
315 | The following scopes MUST be supported:
316 |
317 | - `openid`: As described as [section 3.1.2.1](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest) of **[OIDC]**, this scope MUST be present on each authentication request.
318 | - `profile`: Data Holders MUST support the `profile` scope as described in [section 5.4](https://openid.net/specs/openid-connect-core-1_0.html#ScopeClaims) of **[OIDC]**. This scope MAY be present on an authentication request.
319 |
320 | ## 8.2. Claims
321 | The following [normal](https://openid.net/specs/openid-connect-core-1_0.html#NormalClaims) **[OIDC]** claims MUST be supported. This list includes, but is not limited to, **[OIDC]** [standard claims](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) :
322 |
323 | - `sub`: [Pairwise Pseudonymous Identifier (PPID)](#identifiers) for the End-User at the Data Holder.
324 | - `acr`: Authentication Context Class Reference. MUST contain a valid [ordinal LoA value](#ordinal-loa).
325 | - `auth_time`: Time when the End-User authentication occurred. Its value is a JSON number representing the number of seconds from 1970-01-01T00:00:00Z to the UTC `auth_time`.
326 | - `name`: End-User's full name in displayable form including all name parts.
327 | - `given_name`: Given name(s) or first name(s) of the End-User.
328 | - `family_name`: Surname(s) or last name(s) of the End-User.
329 | - `updated_at`: Time the End-User's information was last updated. Its value is a JSON number representing the number of seconds from 1970-01-01T00:00:00Z to the UTC `updated_at` time.
330 |
331 | The following **[VOT]** claims MAY be supported:
332 |
333 | - `vot`: MUST contain a valid [VoT value](#vector-loas).
334 | - `vtm`: The **[VOT]** trustmark URI.
335 |
336 |
337 | # 9. Identifiers and Subject Types
338 | The identifier for an authenticated end-user (subject) MUST be passed in the `sub` claim of an [ID Token](https://openid.net/specs/openid-cocnnect-core-1_0.html#IDToken) and [UserInfo response](https://openid.net/specs/openid-connect-core-1_0.html#UserInfoResponse) as defined by **[OIDC]**. The
339 | Data Holder MUST generate the `sub` value as a Pairwise Pseudonymous Identifier (PPID)
340 | as described in [section 8](https://openid.net/specs/openid-connect-core-1_0.html#SubjectIDTypes) of **[OIDC]**. Furthermore, the identifier SHOULD also be unique relative to the scenario in which the end-user has authenticated. For example, the identifier generated for the same person when they are using a business account SHOULD be different to the identifier that is generated when that same individual is authorising as an individual.
341 |
342 | It is RECOMMENDED that the `sub` value is generated as a universally unique
343 | Identifier (UUID) **[RFC4122]**.
344 |
345 |
346 | # 10. Levels of Assurance (LoAs)
347 | Levels Of Assurance (LoAs), returned after a successful authentication, MAY be represented in 2 different forms:
348 |
349 | - [Single Ordinal](#ordinal-loa): A single LoA value is represented.
350 | - Data Holder's MUST support this mechanism.
351 | - [Vector](#vector-loas): One or more LoAs, represented by a vector value, are represented.
352 | - Data Holder's MAY support this mechanism.
353 |
354 |
355 | ## 10.1. Single Ordinal
356 | A Single LoA value is carried in the `acr` claim which is described in [section 2](https://openid.net/specs/openid-connect-core-1_0.html#IDToken) of **[OIDC]**.
357 |
358 | - An LoA of 2 is represented by the URI: `urn:cds.au:cdr:2`
359 | - The authenticator used to attain this level MUST conform with the Credential Level `CL1` rules specified under the [Trusted Digital Identity Framework](https://www.dta.gov.au/our-projects/digital-identity/join-identity-federation/accreditation-and-onboarding/trusted-digital-identity-framework
360 | ) **[TDIF]** Authentication Credential Requirements specification.
361 |
362 |
363 | - An LoA of 3 is represented by the URI: `urn:cds.au:cdr:3`
364 | - The authenticators used to attain this level MUST conform with the Credential Level `CL2` rules specified under the [Trusted Digital Identity Framework](https://www.dta.gov.au/our-projects/digital-identity/join-identity-federation/accreditation-and-onboarding/trusted-digital-identity-framework
365 | ) **[TDIF]** Authentication Credential Requirements specification.
366 |
367 | *READ* operations SHALL only be allowed where __at least__ an LoA of 2 has been achieved.
368 |
369 | *WRITE* operations SHALL only be allowed where __at least__ an LoA of 3 has been achieved.
370 |
371 |
372 | ## 10.2. Vector
373 |
374 | ## 10.2.1. Overview
375 | This profile incorporates support for [Vectors of Trust](https://tools.ietf.org/html/draft-richer-vectors-of-trust-15) **[VOT]**. A Vector, in this context, allows for the representation of multiple orthogonal components dimensions that may, but are not limited to, carry information relating to:
376 |
377 | - Identity Proofing
378 | - Primary Credential Usage
379 | - Primary Credential Management
380 | - Assertion/Federation Presentation
381 |
382 | It is anticipated that due to their characteristics, which include composability, extensibility, and expressiveness, VoTs will be become the relevant standard for assurance representation at Identity Providers. Furthermore, as the **[CDR]** matures and incorporates requirements for Identity Proofing, Credential Management, and Assertion Presentation, these independent LoAs will be progressively added to the VoT **[CDR]** ecosystem. However, the dynamic capabilities of **[VOT]** will ensure that their addition does not break existing **[CDR]** implementations.
383 |
384 |
385 | ## 10.2.2. VoT Values
386 |
387 | The following VoT values SHALL be supported to represent authentication assurance levels when employing **[VOT]**. These are carried in the `vot` claim of an ID Token:
388 |
389 | - `CL1`: This is Credential Level CL1 [defined](https://www.dta.gov.au/our-projects/digital-identity/join-identity-federation/accreditation-and-onboarding/trusted-digital-identity-framework) by the **[TDIF]** Authentication Credential Requirements specification.
390 |
391 | - `CL2`: This is Credential Level CL2 [defined](https://www.dta.gov.au/our-projects/digital-identity/join-identity-federation/accreditation-and-onboarding/trusted-digital-identity-framework) by the **[TDIF]** Authentication Credential Requirements specification.
392 |
393 | *READ* operations SHALL only be allowed where __at least__ a `CL1` has been provided.
394 |
395 | *WRITE* operations SHALL only be allowed where __at least__ a `CL2` has been provided.
396 |
397 |
400 |
401 | # 11. Transaction Security
402 | ## 11.1. Ciphers
403 | All HTTP calls MUST be made using HTTPS incorporating TLS >= 1.2. Only the following cipher suites SHALL be permitted in accordance with [section 8.5](https://openid.net/specs/openid-financial-api-part-2.html#tls-considerations) of **[FAPI-RW]**:
404 |
405 | - TLS\_DHE\_RSA\_WITH\_AES\_128\_GCM\_SHA256
406 | - TLS\_ECDHE\_RSA\_WITH\_AES\_128\_GCM\_SHA256
407 | - TLS\_DHE\_RSA\_WITH\_AES\_256\_GCM\_SHA384
408 | - TLS\_ECDHE\_RSA\_WITH\_AES\_256\_GCM\_SHA384
409 |
410 |
411 | ## 11.2. Mutual TLS
412 |
413 |
416 |
417 | All back-channel communication between Data Recipient and Data Holder systems MUST incorporate, unless stated otherwise, MTLS as part of the TLS handshake:
418 |
419 | - The presented Client transport certificate MUST be issued by the CDR Certificate Authority (CA). The Server MUST NOT trust Client transport certificates issued by other authorities.
420 | - The presented Server transport certificate MUST be issued by the CDR Certificate Authority (CA). The Client MUST NOT trust Server transport certificates issued by other authorities.
421 |
422 | ## 11.3. Holder of Key Mechanism
423 |
424 | MTLS MUST be supported as a Holder of Key (HoK) Mechanism.
425 |
426 | OAUTB SHALL NOT be supported due to a lack industry support.
427 |
428 | MTLS HoK allows issued tokens to be bound to a client certificate as specified in [section 3](https://tools.ietf.org/id/draft-ietf-oauth-mtls-07.html#SenderConstrainedAccess) of **[MTLS]**.
429 |
430 |
431 | # 12. Request Object
432 |
433 | > Non-Normative Example - acr as an Essential Claim
434 |
435 | ```
436 | #Decoded Request Object JWT
437 |
438 | {
439 | "alg": "PS256",
440 | "typ": "JWT",
441 | "kid": "123"
442 | }
443 | {
444 | "aud": "https://www.recipient.com.au",
445 | "response_type": "code id_token",
446 | "client_id": "12345",
447 | "redirect_uri": "https://www.recipient.com.au/coolstuff",
448 | "scope": "openid",
449 | "state": "af0ifjsldkj",
450 | "nonce": "n-0S6_WzA2Mj",
451 | "claims": {
452 | "id_token": {
453 | "cdr_consent_id": {
454 | "value": "adceecd3-3437-4369-909e-1ac82abdc288",
455 | "essential": true
456 | },
457 | "acr": {
458 | "essential": true,
459 | "values": ["urn:cds.au:cdr:3"]
460 | }
461 | },
462 | "userinfo": {
463 | "cdr_consent_id": {
464 | "value": "adceecd3-3437-4369-909e-1ac82abdc288",
465 | "essential": true
466 | },
467 | "given_name": null,
468 | "family_name": null
469 | }
470 | }
471 | }
472 | ```
473 |
474 | The Request Object is a signed and encoded JWT specified in [section 6.1](https://openid.net/specs/openid-connect-core-1_0.html#RequestObject) of **[OIDC]**. As per **[FAPI-RW]** [section 5.2.2](https://openid.net/specs/openid-financial-api-part-2.html#authorization-server) and **[FAPI-CIBA]** [section 5.2.2](https://bitbucket.org/openid/fapi/src/master/Financial_API_WD_CIBA.md?fileviewer=file-view-default#markdown-header-522-authorization-server), the `request` parameter MUST be present on requests to both the **[OIDC]** Hybrid Authorisation Endpoint and **[FAPI-CIBA]** Backchannel Authorisation Endpoint. The Request Object enables **[OIDC]** requests to be passed in a single and self-contained parameter.
475 |
476 | Request Objects MUST be signed by Data Recipients as specified in [section 8.6](https://openid.net/specs/openid-financial-api-part-2.html#jws-algorithm-considerations) of **[FAPI-RW]**.
477 |
478 | Data Recipients MUST include a `cdr_consent_id` value in the Request Object. A high-level overview of consent is provided in the [section 14](#consent) of this artifact.
479 |
480 | Data Holder Authorisation Servers MUST treat a Request Object that does not contain a `cdr_consent_id` as an essential claim as invalid.
481 |
482 | Request Object references SHALL NOT be supported.
483 |
484 | The `iss` claim SHALL NOT be supported as it duplicates the role of the `client_id` claim.
485 |
486 | ## 12.1. Data Holder Authorisation Server VoT
487 |
488 | > Non-Normative Example - vtr
489 |
490 | ```
491 | Decoded Request Object JWT
492 | {
493 | "alg": "PS256",
494 | "typ": "JWT",
495 | "kid": "123"
496 | }
497 | {
498 | "aud": "https://www.recipient.com.au",
499 | "response_type": "code id_token",
500 | "client_id": "12345",
501 | "redirect_uri": "https://www.recipient.com.au/coolstuff",
502 | "scope": "openid",
503 | "state": "af0ifjsldkj",
504 | "nonce": "n-0S6_WzA2Mj",
505 | "vtr":" "CL2 CL1",
506 | "claims": {
507 | "id_token": {
508 | "cdr_consent_id": {
509 | "value": "adceecd3-3437-4369-909e-1ac82abdc288",
510 | "essential": true
511 | }
512 | },
513 | "userinfo": {
514 | "cdr_consent_id": {
515 | "value": "adceecd3-3437-4369-909e-1ac82abdc288",
516 | "essential": true
517 | },
518 | "given_name": null,
519 | "family_name": null
520 | }
521 | }
522 | }
523 | ```
524 |
525 | If a Data Holder supports Vectors of Trust **[VOT]**, they MUST accept Request objects which MAY contain:
526 |
527 | - A `vtr` value.
528 | - Allowed Values are specified in the [VoT values section](#vot-values) of this artifact.
529 | - This value MUST contain a space-separated string that specifies the `vot` values that the Authorization Server is being requested to use for processing this Authentication Request, with the values appearing in order of preference. The VoT satisfied by the authentication performed is returned as the `vot` Claim Value.
530 | - The `vot` Claim is requested as a Voluntary Claim by this parameter.
531 | - The `vtr` takes precedence over `acr_values`
532 | - A `vot` essential claim.
533 | - This is the VoT equivalent of an `acr` essential claim.
534 | - If the `vot` Claim is requested as an Essential Claim for the ID Token with a values parameter requesting specific VoT values, the Data Holder Authorization Server MUST return a `vot` Claim Value that matches one of the requested values. The Data Holder Authorization Server MAY ask the End-User to re-authenticate with additional factors to meet this requirement. If this requirement cannot be met, then the Data Holder Authorization Server MUST treat that outcome as a failed authentication.
535 |
536 | ## 12.2. Data Recipient Client using VoT
537 |
538 | > Non-Normative Example - vot as an Essential Claim
539 |
540 | ```
541 | Decoded Request Object JWT
542 | {
543 | "alg": "PS256",
544 | "typ": "JWT",
545 | "kid": "123"
546 | }
547 | {
548 | "aud": "https://www.recipient.com.au",
549 | "response_type": "code id_token",
550 | "client_id": "12345",
551 | "redirect_uri": "https://www.recipient.com.au/coolstuff",
552 | "scope": "openid",
553 | "state": "af0ifjsldkj",
554 | "nonce": "n-0S6_WzA2Mj",
555 | "claims": {
556 | "id_token": {
557 | "vot": {
558 | "essential": true,
559 | "values": ["CL2"]
560 | },
561 | "cdr_consent_id": {
562 | "value": "adceecd3-3437-4369-909e-1ac82abdc288",
563 | "essential": true
564 | }
565 | }
566 | }
567 | }
568 | ```
569 |
570 | For *WRITE* operations, a Data Recipient:
571 |
572 | - SHALL, where a Data Holder supports **[VOT]**, request user authentication with a Credential Level of 2 (`CL2`) or greater by requesting the `vot` claim as an essential claim.
573 |
574 | # 13. Endpoints
575 |
576 | ## 13.1. OpenID Provider Configuration Endpoint
577 |
578 | > Non-Normative Example
579 |
580 | ```
581 | # Request
582 |
583 | GET /.well-known/openid-configuration HTTP/1.1
584 | Host: www.dh.com.au
585 |
586 | # Response
587 |
588 | HTTP/1.1 200 OK
589 | Content-Type: application/json
590 | {
591 | "issuer": "https://www.dh.com.au",
592 | "authorization_endpoint": "https://www.dh.com.au/authorise",
593 | "token_endpoint": "https://www.dh.com.au/token",
594 | "introspection_endpoint": "https://www.dh.com.au/introspect",
595 | "revocation_endpoint": "https://www.dh.com.au/revoke",
596 | "userinfo_endpoint": "https://www.dh.com.au/userinfo",
597 | "jwks_uri": "https://www.dh.com.au/jwks",
598 | "registration_endpoint": "https://www.dh.com.au/register",
599 | "backchannel_authentication_endpoint": "https://www.dh.com.au/bc-authorise",
600 | "backchannel_token_delivery_modes_supported": ["poll", "ping"],
601 | "backchannel_authentication_request_signing_alg_values_supported": ["ES256", "PS256"],
602 | "scopes_supported": ["openid", "profile"],
603 | "response_types_supported": ["code id_token"],
604 | "response_modes_supported": ["fragment"],
605 | "grant_types_supported": ["authorization_code", "client_credentials", "urn:openid:params:modrna:grant-type:backchannel_request"],
606 | "acr_values_supported": ["urn:cds.au:cdr:2","urn:cds.au:cdr:3"],
607 | "vot_values_supported": ["CL1","CL2"],
608 | "subject_types_supported": ["pairwise"],
609 | "id_token_signing_alg_values_supported": ["ES256", "PS256"],
610 | "request_object_signing_alg_values_supported": ["ES256", "PS256"],
611 | "token_endpoint_auth_methods_supported": ["private_key_jwt"],
612 | "mutual_tls_sender_constrained_access_tokens": "true",
613 | "claims_supported": ["name", "given_name", "family_name", "vot", "acr", "auth_time", "sub"]
614 | }
615 | ```
616 |
617 |
620 |
621 | | Description | Value |
622 | |---|---|
623 | | Hosted By | Data Holder |
624 | | Transport Security | TLS |
625 | | Client Authentication Required| No|
626 | | Bearer Token Required| No|
627 |
628 | Data Holders MUST make their OpenID Provider Metadata available via a configuration endpoint as outlined in [Section 3 and 4 of the OpenID Connect Discovery standards] (https://openid.net/specs/openid-connect-discovery-1_0.html) **[OIDD]**.
629 |
630 | Where a Data Holder is supporting [Vectors of Trust](https://tools.ietf.org/html/draft-richer-vectors-of-trust-15) **[VOT]** or [FAPI-CIBA](https://bitbucket.org/openid/fapi/src/master/Financial_API_WD_CIBA.md?fileviewer=file-view-default) **[FAPI-CIBA]**, the published OpenID Provider metadata SHALL reflect that support.
631 |
632 | At a minimum, the Data Provider metadata MUST include:
633 |
634 | - `issuer`: URL that the Data Holder asserts as its Issuer Identifier.
635 | - `authorization_endpoint`: URL of the Authorization Endpoint.
636 | - `token_endpoint`: URL of the Token Endpoint.
637 | - `introspection_endpoint`: URL of the Introspection Endpoint.
638 | - `revocation_endpoint`: URL of the Revocation Endpoint.
639 | - `userinfo_endpoint`: URL of the UserInfo Endpoint.
640 | - `jwks_uri`: URL of the JWKS Endpoint.
641 | - `scopes_supported`: This list of supported scopes.
642 | - `claims_supported`: The list of supported claims.
643 | - `acr_values_supported`: The supported ACR values.
644 |
645 | Data Holders that support [Vectors of Trust](https://tools.ietf.org/html/draft-richer-vectors-of-trust-15) **[VOT]** MUST include:
646 |
647 | - `vot_values_supported`: The list of supported component values.
648 |
649 | Data Holders that support [CIBA](https://bitbucket.org/openid/fapi/src/master/Financial_API_WD_CIBA.md?fileviewer=file-view-default) **[FAPI-CIBA]** MUST include:
650 |
651 | - `backchannel_authentication_endpoint`: The CIBA Authorisation Endpoint.
652 | - `backchannel_authentication_request_signing_alg_values_supported`: JSON array containing a list of the JWS signing algorithms (alg values) supported by the OP for signed authentication requests. Only `ES256` and `PS256` SHALL be supported.
653 |
654 |
655 | ## 13.2. Authorisation Endpoint
656 |
657 | > Non-Normative Example
658 |
659 | ```
660 | # Request
661 |
662 | GET /authorise?
663 | response_type=code%20id_token
664 | &client_id=12345
665 | &redirect_uri=https%3A%2F%2Fwww.recipient.com.au%2Fcoolstuff
666 | &scope=openid%20profile
667 | &nonce=n-0S6_WzA2Mj
668 | &state=af0ifjsldkj HTTP/1.1
669 | &request=eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMyJ9.ey ...
670 | Host: www.holder.com.au
671 |
672 | # Decoded request JWT
673 | {
674 | "alg": "PS256",
675 | "typ": "JWT",
676 | "kid": "123"
677 | }
678 | {
679 | "iss": "12345",
680 | "aud": "https://www.recipient.com.au",
681 | "response_type": "code id_token",
682 | "client_id": "12345",
683 | "redirect_uri": "https://www.recipient.com.au/coolstuff",
684 | "scope": "openid",
685 | "state": "af0ifjsldkj",
686 | "nonce": "n-0S6_WzA2Mj",
687 | "claims": {
688 | "userinfo": {
689 | "cdr_consent_id": {
690 | "value": "adceecd3-3437-4369-909e-1ac82abdc288",
691 | "essential": true
692 | },
693 | "given_name": null,
694 | "family_name": null
695 | },
696 | "id_token": {
697 | "cdr_consent_id": {
698 | "value": "adceecd3-3437-4369-909e-1ac82abdc288",
699 | "essential": true
700 | },
701 | "acr": {
702 | "values": ["urn:cds.au:cdr:3"]
703 | }
704 | }
705 | }
706 | }
707 |
708 | ```
709 |
710 | | Description | Value |
711 | |---|---|
712 | | Hosted By | Data Holder |
713 | | Transport Security | TLS |
714 | | Client Authentication Required| No|
715 | | Bearer Token Required| No|
716 |
717 | The requirements for the Authorisation Endpoint are specified in [section 3.3.2] (https://openid.net/specs/openid-connect-core-1_0.html#HybridAuthorizationEndpoint) of **[OIDC]** and further specified under section [5.2.2](https://openid.net/specs/openid-financial-api-part-2.html#authorization-server) of **[FAPI-RW]**. This endpoint is invoked as part of the [Hybrid Authentication flow](#hybrid-flow).
718 |
719 | Only a `response_type` (see [section 3](https://openid.net/specs/openid-connect-core-1_0.html#Authentication) of **[OIDC]**) of `code id_token` SHALL be allowed.
720 |
721 | The `request_uri` parameter SHALL NOT be supported.
722 |
723 | A description of requirements relating to the `request` parameter can be found in the [section 12](#request-object).
724 |
725 | ## 13.3. Backchannel Authorisation Endpoint
726 | | Description | Value |
727 | |---|---|
728 | | Hosted By | Data Holder |
729 | | Transport Security | MTLS |
730 | | Client Authentication Required| Yes|
731 | | Bearer Token Required| No|
732 |
733 | The requirements for the Backchannel Authorisation Endpoint are specified in the [Client Initiated Backchannel Authentication Profile](https://bitbucket.org/openid/fapi/src/master/Financial_API_WD_CIBA.md?fileviewer=file-view-default#markdown-header-523-confidential-client) **[FAPI-CIBA]**. This endpoint is invoked as part of the [Client-Initiated Backchannel Authentication flow](#ciba-flow).
734 |
735 | Data Holder's that feature **[FAPI-CIBA]** MUST support the `poll` mode and MAY support the `ping` mode. The `push` mode SHALL not be supported.
736 |
737 | A description of requirements relating to the `request` parameter can be found in the [section 12](#request-object).
738 |
739 | ## 13.4. Token Endpoint
740 | | Description | Value |
741 | |---|---|
742 | | Hosted By | Data Holder |
743 | | Transport Security | MTLS |
744 | | Client Authentication Required| Yes|
745 | | Bearer Token Required| No|
746 |
747 | The requirements for the Token Endpoint are specified in [section 5.3] (https://openid.net/specs/openid-connect-core-1_0.html#UserInfo) of **[OIDC]**.
748 |
749 | To obtain an Access Token, an ID Token, and a Refresh Token, the Data Recipient sends a Token Request to the Token Endpoint.
750 |
751 | Data Holders MUST support a Token Endpoint.
752 |
753 | ## 13.5. UserInfo Endpoint
754 | | Description | Value |
755 | |---|---|
756 | | Hosted By | Data Holder |
757 | | Transport Security | MTLS |
758 | | Client Authentication Required| No|
759 | | Bearer Token Required| Yes|
760 |
761 | The requirements for the UserInfo Endpoint are specified in [section 3.3.3] (https://openid.net/specs/openid-connect-core-1_0.html#HybridTokenEndpoint) of **[OIDC]**.
762 |
763 | Data Holders MUST support a UserInfo Endpoint.
764 |
765 | ## 13.6. JWKS Endpoint
766 |
767 | > Non-Normative Example
768 |
769 | ```
770 | {
771 | "keys": [
772 | {
773 | "kty":"EC",
774 | "crv":"P-256",
775 | "x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4",
776 | "y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM",
777 | "use":"enc",
778 | "kid":"1"
779 | }
780 | ]
781 | }
782 | ```
783 |
784 |
787 |
788 |
791 |
792 | | Description | Value |
793 | |---|---|
794 | | Hosted By | Registry |
795 | | Transport Security | TLS |
796 | | Client Authentication Required| No|
797 | | Bearer Token Required| No|
798 |
799 | The JWKS Endpoint returns a **[JSON]** document containing a JSON Web Key Set described in [section 5](https://tools.ietf.org/html/rfc7517#section-5) of **[JWK]**. The JWK format is described in [section 4](https://tools.ietf.org/html/rfc7517#section-4) of **[JWK]**. In addition to the mandatory fields specified in **[JWK]**, each JWK MUST include, at a minimum, the following fields:
800 |
801 | - `kid`: This is used to match a specific key within a JWKS and thus must be unique within the set.
802 | - `use`: This is used to identify the intended use of the public key. Supported values are `sig` and `enc`.
803 |
804 | ## 13.7. Introspection Endpoint
805 |
806 | | Description | Value |
807 | |---|---|
808 | | Hosted By | Data Holder |
809 | | Transport Security | MTLS |
810 | | Client Authentication Required| Yes|
811 | | Bearer Token Required| No|
812 |
813 | Data Holders MUST implement an Introspection Endpoint to allow Data Recipients to determine the status and expiry date of Refresh Tokens. The requirements for an Introspection Endpoint are described in [section 2](https://tools.ietf.org/html/rfc7662#section-2) of **[RFC7662]**.
814 |
815 | Introspection of Refresh Tokens MUST be supported.
816 |
817 | Introspection of Access Tokens and ID Tokens MUST NOT be supported.
818 |
819 | An Introspection Endpoint Response SHALL only include the following fields:
820 |
821 | - `active`: Boolean indicator of whether or not the presented token
822 | is currently active.
823 | - `exp`: A JSON number representing the number of seconds from 1970-01-01T00:00:00Z to the UTC expiry time.
824 |
825 | ## 13.8. Revocation Endpoint
826 |
827 | | Description | Value |
828 | |---|---|
829 | | Hosted By | Data Holder |
830 | | Transport Security | MTLS |
831 | | Client Authentication Required| Yes|
832 | | Bearer Token Required| No|
833 |
834 | Data Holders MUST implement a Token Revocation Endpoint as described in [section 2](https://tools.ietf.org/html/rfc7009#section-2) of **[RFC7009]**. The Revocation Endpoint serves as a revocation mechanism that allows a Data Recipient to invalidate its tokens as required. Notifying the Data Holder authorisation server that the token is no longer needed allows the server to clean up data associated with that token and the underlying authorization grant.
835 |
836 | Revocation of Refresh Tokens and Access Tokens MUST be supported.
837 |
838 | ## 13.9. Client Registration Endpoint
839 |
840 | > Non-Normative Example
841 |
842 | ```
843 | # Request
844 |
845 | POST /clients HTTP/1.1
846 | Content-Type: application/jwt
847 | Accept: application/json
848 | Host: www.holder.com.au
849 |
850 | eyJhbGciOiJQUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IjEyMzQ1In0.ey ...
851 |
852 | # Decoded request JWT
853 | {
854 | "alg": "PS256",
855 | "typ": "JWT",
856 | "kid": "12345"
857 | }
858 | {
859 | "iss": "https://www.recipient.com.au",
860 | "iat": 1516239022,
861 | "exp": 1516239322,
862 | "aud": "https://www.holder.com.au",
863 | "jti": "37747cd1-c105-4569-9f75-4adf28b73e31",
864 | "redirect_uris": ["https://www.recipient.com.au/coolstuff"],
865 | "token_endpoint_auth_method": "private_key_jwt",
866 | "grant_types": ["authorization_code","client_credentials"],
867 | "response_types": "code",
868 | "software_statement": "encodedsignedjwt",
869 | "id_token_signed_response_alg":"PS256",
870 | "request_object_signing_alg":"PS256"
871 | }
872 |
873 | # Response
874 |
875 | HTTP/1.1 201 OK
876 | Content-Type: application/json
877 | {
878 | "client_id": "12345",
879 | "client_name": "Awesome Recipient Software",
880 | "redirect_uris": ["https://www.recipient.com.au/coolstuff"],
881 | "token_endpoint_auth_method": "private_key_jwt",
882 | "grant_types": ["authorization_code","client_credentials"],
883 | "response_types": "code",
884 | "id_token_signed_response_alg":"PS256",
885 | "request_object_signing_alg":"PS256"
886 | }
887 | ```
888 |
889 |
892 |
893 | | Description | Value |
894 | |---|---|
895 | | Hosted By | Data Holder |
896 | | Transport Security | MTLS |
897 | | Client Authentication Required| No|
898 | | Bearer Token Required| No|
899 |
900 | ### 13.9.1. Request
901 |
902 | To register as a new Client at a Data Holder's Authorisation Server, a Data Recipient MUST `POST` its Client metadata to the Data Holder's Registration Endpoint in the form of an (encoded) signed [JWT](https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32) **[JWT]**. This process is specified in [OpenID Connect Registration](https://openid.net/specs/openid-connect-registration-1_0.html) **[OIDC-CR]**. The registering **[JWT]** is signed by the private key of the Client and MUST include a [software statement](https://tools.ietf.org/html/rfc7591#page-14). The software statement is an encoded [JWT](https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32) **[JWT]** signed by the CDR Certificate Authority private key and thus supports non-repudiation. The content of and mechanism for retrieving and generating a software statement is beyond the scope of this profile.
903 |
904 | The registering **[JWT]** MUST include, at a minimum, the following fields:
905 |
906 | - `iss`: The Data Recipient identifier specified at the Registry.
907 | - `iat`: A JSON number representing the number of seconds from 1970-01-01T00:00:00Z to the UTC issued at time.
908 | - `exp`: A JSON number representing the number of seconds from 1970-01-01T00:00:00Z to the UTC expiry time.
909 | - `aud`: The Data Holder identifier specified at the Registry.
910 | - `jti`: A unique identifier generated by the Data Recipient.
911 | - `redirect_uris`: An Array of Redirection URI values.
912 | - `software_statement`: This is an encoded JWT which includes several claims that describe the Data Recipient application and the Data Recipient organisation.
913 | - `id_token_signed_response_alg`: Token Endpoint preferred signing algorithm.
914 | - `request_object_signing_alg`: Request Object signing algorithm.
915 | - `token_endpoint_auth_method`: The chosen Client authentication mechanism.
916 |
917 | If the Data Holder supports [FAPI-CIBA](https://bitbucket.org/openid/fapi/src/master/Financial_API_WD_CIBA.md?fileviewer=file-view-default) **[FAPI-CIBA]** and the Client wishes to utilise this feature, the registration MUST include the following fields:
918 |
919 | - `backchannel_token_delivery_mode`: This MUST be set to a value of `ping` or `poll`. `push` mode SHALL NOT be supported.
920 | - `backchannel_authentication_request_signing_alg`: MUST be set to `ES256` or `PS256`.
921 |
922 | If the Client supports a delivery mode of `ping`, the registration MUST include the following fields:
923 |
924 | - `backchannel_client_notification_endpoint`: This is the endpoint to which the OP will post a notification after a successful or failed end-user authentication.
925 |
926 | This request MUST be made with MTLS as specified in [section 11.2](#mutual-tls).
927 |
928 | Data Holders MUST ensure that the `CN` (Common Name) in the Client certificate `subject` field matches the `software_id` claim present in the software statement.
929 | Data Holders MUST verify that the embedded software statement has been signed by the CDR Certificate Authority.
930 |
931 | ### 13.9.2. Response
932 |
933 | The Data Holder MUST respond in accordance with [OpenID Connect Registration](https://openid.net/specs/openid-connect-registration-1_0.html) **[OIDC-CR]** sections 3.2 and 3.3.
934 |
935 |
936 | # 14. Consent
937 |
938 |
941 |
942 | Prior to initiating an authentication request to a Data Holder's Authorisation Server, a Data Recipient MUST have captured indicative Consumer Consent and passed this to the Data Holder. A Consent occurrence is assigned a unique `cdr_consent_id` and is referenced by the Data Holder as part of an authorisation process with a Consumer. This process binds the Consent to the authorisation. In order to support this functionality, a Data Holder MUST implement and host an API to support the creation of a Consent, the querying of a Consent, and the deletion of a Consent. In this instance the Data Recipient is to be considered the Resource Owner of the Consent occurrence.
943 |
944 | The specifics of the Consent API and processing of Consent are beyond the scope of this document.
945 |
946 | A Data Holder Token Endpoint MUST:
947 |
948 | - Support the `grant type` of `client_credentials` strictly for the purpose of passing an Access Token to a Data Recipient which can be then used to invoke the Consent API.
949 |
950 |
951 | # 15. Normative References
952 |
953 | | **Reference** | **Description** |
954 | | --- | --- | --- |
955 | | **[CIBA]** | OpenID Connect Client Initiated Backchannel Authentication Flow - Core 1.0 draft-01: |
956 | | **[FAPI-CIBA]** | Financial Services – Financial API: Client Initiated Backchannel Authentication Profile 1.0: |
957 | | **[FAPI-R]** | Financial-grade API - Part 1: Read Only API Security Profile: |
958 | | **[FAPI-RW]** | Financial-grade API - Part 2: Read and Write API Security Profile: |
959 | | **[JSON]** | The JavaScript Object Notation (JSON) Data Interchange Format: |
960 | | **[JWA]** | JSON Web Algorithms (JWA): |
961 | | **[JWK]** | JSON Web Key (JWK): |
962 | | **[JWT]** | JSON Web Token (JWT): |
963 | | **[JWS]** | JSON Web Signature (JWS): |
964 | | **[JWE]** | JSON Web Encryption (JWE): |
965 | | **[MTLS]** | OAuth 2.0 Mutual TLS Client Authentication and Certificate Bound Access Tokens: |
966 | | **[OAUTH2]** | The OAuth 2.0 Authorization Framework: |
967 | | **[OIDC]** | OpenID Connect Core 1.0 incorporating errata set 1: |
968 | | **[OIDD]** | OpenID Connect Discovery 1.0 incorporating errata set 1: |
969 | | **[OIDC-CR]** | OpenID Connect Dynamic Client Registration 1.0 incorporating errata set 1: |
970 | | **[TDIF]** | Digital Transformation Agency - Trusted Digital Identity Framework
971 | | **[RFC2119]** | Key words for use in RFCs to Indicate Requirement Levels |
972 | | **[RFC7009]** | OAuth 2.0 Token Revocation: |
973 | | **[RFC7523]** | JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants: |
974 | | **[RFC7662]** | OAuth 2.0 Token Introspection: |
975 | | **[VOT]** | Vectors of Trust, draft-richer-vectors-of-trust-15
976 |
977 | # 16. Informative References
978 |
979 | | **Reference** | **Description** |
980 | |----------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
981 | | **[BCP195]** | Recommendations for Secure Use of Transport Layer Security (TLS) and Datagram Transport Layer Security (DTLS):
982 | | **[CDR]** | Consumer Data Right: |
983 | | **[FAPI]** | Financial-Grade API - Home Page |
984 | | **[RFC4122]** | A Universally Unique Identifier (UUID) URN Namespace: |
985 | | **[X.1254]** | X.1254 - Entity authentication assurance framework: |
986 |
987 | # 17. Appendix
988 |
989 | ## 17.1. Client Credentials grant type
990 | 
991 |
992 | ## 17.2. Redirect Authentication Flow
993 |
994 | ### Part A - Data Recipient to Data Holder
995 | 
996 | #### Steps
997 | 1. The end-user navigates to a Data Recipient Website.
998 | 2. The end-user selects their preferred Data Holder.
999 | 3. The end-user's browser is redirected to the Data Holder's Authorisation Endpoint.
1000 | 4. *One* of the following may occur:
1001 | 1. The end-user may cancel the process at any point (in Parts **A**, **B** or **C**) and will be returned to the passed redirection URI for the Data Recipient with the relevant error code.
1002 | 2. The end-user is denied access. This may happen as a result of too many failed attempts or other conditions relating to the end-user's account. The end-user's browser will be redirected to the passed redirection URI for the Data Recipient with the relevant error code.
1003 | 3. The end-user successfully authenticates and begins the authorisation step (see Part **B**).
1004 |
1005 |
1006 | ### Part B - Data Holder Authentication
1007 | 
1008 | #### Steps
1009 | Part **B** illustrates the different authentication methods a Data Holder may present to the end-user. It is important from a usability perspective that the Data Holder authentication choices presented to the end-user are consistent with those currently utilised by the end-user when accessing their existing Data Holder online accounts.
1010 |
1011 | The following options may be used:
1012 |
1013 | 1. All Credentials/Factors are captured through the Browser. On success, the authorisation process begins (Part **C**) .
1014 | 2. Two Factor Authentication (2FA)
1015 | 1. A userId and optionally a password are entered to the browser and submitted by the end-user.
1016 | 2. A code or notification is sent to a end-user's pre-registered mobile/device application (detached authentication device). This step is optional as an end-user's device application may generate codes in isolation, as is the case for Time-based One-Time Password (TOTP).
1017 | 3. The end-user views the code or event on their detached authentication device.
1018 | 4. *One* of the following may occur:
1019 | 1. The end-user directly enters the code (or scans a QR Code) into the browser and submits the request. On success, the authorisation process begins (Part **C**).
1020 | 2. The end-user does not enter the code into the browser. The end-user acknowledges the authentication through the device and a secure message is sent from the device to the Data Holder via a backchannel. On receipt of the message, the Data Holder's website redirects the end-user's browser to the authorisation page (Part **C**).
1021 |
1022 | ### Part C - Post Authorisation Data Recipient to Data Holder
1023 | 
1024 | #### Steps
1025 | This process continues from Part **B** after a successful authentication.
1026 |
1027 | 1. The end-user authorises the transaction.
1028 | 2. *One* of the following may occur:
1029 | 1. The Data Holder creates a new pairwise identifier for the end-user and Data Recipient combination. This is the first time the end-user has authenticated to the Data Holder in the context of a request from this Data Recipient.
1030 | 2. This is a reauthentication. The end-user has previously authenticated to the Data Holder in the context of an authentication request from this Data Recipient. The existing pairwise identifier for the end-user and Data Recipient is allocated to the authorisation.
1031 | 3. The Data Holder creates the authorisation code and ID Token for the authorisation instance.
1032 | 4. The end-user's browser is redirected to the Data Recipient's redirect URI. The ID Token and authorisation code generated in Step 3 are attached to the URL as a fragment. The Data Recipient web server processes the request.
1033 | 5. The Data Recipient decrypts the ID Token, verifies the signature and issuer of the ID Token, verifies the state/code hashes within the token, and also matches the presented state against its own session state. The Data Recipient then sends a POST request to the Data Holder Token Endpoint using Client Authentication and the Authorisation Code.
1034 | 6. The Data Holder Endpoint authenticates the Data Recipient client and matches the authorisation code. On success, the Endpoint responds with an Access Token, Refresh Token and an ID Token.
1035 | 7. The Data Holder creates an event relating to the authorisation. This event is propagated/handled and may result in shared resource owners being notified about the authorisation.
1036 | 8. The Data Recipient verifies the ID Token and on success, invokes the UserInfo Endpoint using the Access Token as a Bearer Token. The Data Holder verifies the token, applies the necessary Holder of Key verification check and on success, returns the requested UserInfo claims.
1037 | 9. The Data Recipient optionally begins calling the Data Holder APIs with the Access Token and renders the result to the end-user's browser.
1038 |
1039 | ## 17.3. Sample Data Holder Domain Model
1040 | 
1041 | ### Description
1042 | This diagram depicts the domain model of a hypothetical Data Holder. It is in no way prescriptive but illustrates the associations between the authorisation-related entities that may exist within a Data Holder's domain.
1043 |
--------------------------------------------------------------------------------
/slate/source/javascripts/all.js:
--------------------------------------------------------------------------------
1 | //= require ./all_nosearch
2 | //= require ./app/_search
3 |
--------------------------------------------------------------------------------
/slate/source/javascripts/all_nosearch.js:
--------------------------------------------------------------------------------
1 | //= require ./lib/_energize
2 | //= require ./app/_toc
3 | //= require ./app/_lang
4 |
5 | $(function() {
6 | loadToc($('#toc'), '.toc-link', '.toc-list-h2', 10);
7 | setupLanguages($('body').data('languages'));
8 | $('.content').imagesLoaded( function() {
9 | window.recacheHeights();
10 | window.refreshToc();
11 | });
12 | });
13 |
14 | window.onpopstate = function() {
15 | activateLanguage(getLanguageFromQueryString());
16 | };
17 |
--------------------------------------------------------------------------------
/slate/source/javascripts/app/_lang.js:
--------------------------------------------------------------------------------
1 | //= require ../lib/_jquery
2 |
3 | /*
4 | Copyright 2008-2013 Concur Technologies, Inc.
5 |
6 | Licensed under the Apache License, Version 2.0 (the "License"); you may
7 | not use this file except in compliance with the License. You may obtain
8 | a copy of the License at
9 |
10 | http://www.apache.org/licenses/LICENSE-2.0
11 |
12 | Unless required by applicable law or agreed to in writing, software
13 | distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14 | WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15 | License for the specific language governing permissions and limitations
16 | under the License.
17 | */
18 | ;(function () {
19 | 'use strict';
20 |
21 | var languages = [];
22 |
23 | window.setupLanguages = setupLanguages;
24 | window.activateLanguage = activateLanguage;
25 | window.getLanguageFromQueryString = getLanguageFromQueryString;
26 |
27 | function activateLanguage(language) {
28 | if (!language) return;
29 | if (language === "") return;
30 |
31 | $(".lang-selector a").removeClass('active');
32 | $(".lang-selector a[data-language-name='" + language + "']").addClass('active');
33 | for (var i=0; i < languages.length; i++) {
34 | $(".highlight.tab-" + languages[i]).hide();
35 | $(".lang-specific." + languages[i]).hide();
36 | }
37 | $(".highlight.tab-" + language).show();
38 | $(".lang-specific." + language).show();
39 |
40 | window.recacheHeights();
41 |
42 | // scroll to the new location of the position
43 | if ($(window.location.hash).get(0)) {
44 | $(window.location.hash).get(0).scrollIntoView(true);
45 | }
46 | }
47 |
48 | // parseURL and stringifyURL are from https://github.com/sindresorhus/query-string
49 | // MIT licensed
50 | // https://github.com/sindresorhus/query-string/blob/7bee64c16f2da1a326579e96977b9227bf6da9e6/license
51 | function parseURL(str) {
52 | if (typeof str !== 'string') {
53 | return {};
54 | }
55 |
56 | str = str.trim().replace(/^(\?|#|&)/, '');
57 |
58 | if (!str) {
59 | return {};
60 | }
61 |
62 | return str.split('&').reduce(function (ret, param) {
63 | var parts = param.replace(/\+/g, ' ').split('=');
64 | var key = parts[0];
65 | var val = parts[1];
66 |
67 | key = decodeURIComponent(key);
68 | // missing `=` should be `null`:
69 | // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters
70 | val = val === undefined ? null : decodeURIComponent(val);
71 |
72 | if (!ret.hasOwnProperty(key)) {
73 | ret[key] = val;
74 | } else if (Array.isArray(ret[key])) {
75 | ret[key].push(val);
76 | } else {
77 | ret[key] = [ret[key], val];
78 | }
79 |
80 | return ret;
81 | }, {});
82 | };
83 |
84 | function stringifyURL(obj) {
85 | return obj ? Object.keys(obj).sort().map(function (key) {
86 | var val = obj[key];
87 |
88 | if (Array.isArray(val)) {
89 | return val.sort().map(function (val2) {
90 | return encodeURIComponent(key) + '=' + encodeURIComponent(val2);
91 | }).join('&');
92 | }
93 |
94 | return encodeURIComponent(key) + '=' + encodeURIComponent(val);
95 | }).join('&') : '';
96 | };
97 |
98 | // gets the language set in the query string
99 | function getLanguageFromQueryString() {
100 | if (location.search.length >= 1) {
101 | var language = parseURL(location.search).language;
102 | if (language) {
103 | return language;
104 | } else if (jQuery.inArray(location.search.substr(1), languages) != -1) {
105 | return location.search.substr(1);
106 | }
107 | }
108 |
109 | return false;
110 | }
111 |
112 | // returns a new query string with the new language in it
113 | function generateNewQueryString(language) {
114 | var url = parseURL(location.search);
115 | if (url.language) {
116 | url.language = language;
117 | return stringifyURL(url);
118 | }
119 | return language;
120 | }
121 |
122 | // if a button is clicked, add the state to the history
123 | function pushURL(language) {
124 | if (!history) { return; }
125 | var hash = window.location.hash;
126 | if (hash) {
127 | hash = hash.replace(/^#+/, '');
128 | }
129 | history.pushState({}, '', '?' + generateNewQueryString(language) + '#' + hash);
130 |
131 | // save language as next default
132 | localStorage.setItem("language", language);
133 | }
134 |
135 | function setupLanguages(l) {
136 | var defaultLanguage = localStorage.getItem("language");
137 |
138 | languages = l;
139 |
140 | var presetLanguage = getLanguageFromQueryString();
141 | if (presetLanguage) {
142 | // the language is in the URL, so use that language!
143 | activateLanguage(presetLanguage);
144 |
145 | localStorage.setItem("language", presetLanguage);
146 | } else if ((defaultLanguage !== null) && (jQuery.inArray(defaultLanguage, languages) != -1)) {
147 | // the language was the last selected one saved in localstorage, so use that language!
148 | activateLanguage(defaultLanguage);
149 | } else {
150 | // no language selected, so use the default
151 | activateLanguage(languages[0]);
152 | }
153 | }
154 |
155 | // if we click on a language tab, activate that language
156 | $(function() {
157 | $(".lang-selector a").on("click", function() {
158 | var language = $(this).data("language-name");
159 | pushURL(language);
160 | activateLanguage(language);
161 | return false;
162 | });
163 | });
164 | })();
165 |
--------------------------------------------------------------------------------
/slate/source/javascripts/app/_search.js:
--------------------------------------------------------------------------------
1 | //= require ../lib/_lunr
2 | //= require ../lib/_jquery
3 | //= require ../lib/_jquery.highlight
4 | ;(function () {
5 | 'use strict';
6 |
7 | var content, searchResults;
8 | var highlightOpts = { element: 'span', className: 'search-highlight' };
9 | var searchDelay = 0;
10 | var timeoutHandle = 0;
11 |
12 | var index = new lunr.Index();
13 |
14 | index.ref('id');
15 | index.field('title', { boost: 10 });
16 | index.field('body');
17 | index.pipeline.add(lunr.trimmer, lunr.stopWordFilter);
18 |
19 | $(populate);
20 | $(bind);
21 |
22 | function populate() {
23 | $('h1, h2').each(function() {
24 | var title = $(this);
25 | var body = title.nextUntil('h1, h2');
26 | index.add({
27 | id: title.prop('id'),
28 | title: title.text(),
29 | body: body.text()
30 | });
31 | });
32 |
33 | determineSearchDelay();
34 | }
35 | function determineSearchDelay() {
36 | if(index.tokenStore.length>5000) {
37 | searchDelay = 300;
38 | }
39 | }
40 |
41 | function bind() {
42 | content = $('.content');
43 | searchResults = $('.search-results');
44 |
45 | $('#input-search').on('keyup',function(e) {
46 | var wait = function() {
47 | return function(executingFunction, waitTime){
48 | clearTimeout(timeoutHandle);
49 | timeoutHandle = setTimeout(executingFunction, waitTime);
50 | };
51 | }();
52 | wait(function(){
53 | search(e);
54 | }, searchDelay );
55 | });
56 | }
57 |
58 | function search(event) {
59 |
60 | var searchInput = $('#input-search')[0];
61 |
62 | unhighlight();
63 | searchResults.addClass('visible');
64 |
65 | // ESC clears the field
66 | if (event.keyCode === 27) searchInput.value = '';
67 |
68 | if (searchInput.value) {
69 | var results = index.search(searchInput.value).filter(function(r) {
70 | return r.score > 0.0001;
71 | });
72 |
73 | if (results.length) {
74 | searchResults.empty();
75 | $.each(results, function (index, result) {
76 | var elem = document.getElementById(result.ref);
77 | searchResults.append("