├── .clang-format
├── .clang-tidy
├── .cmake-format
├── .editorconfig
├── .gitattributes
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug-report.yml
│ ├── feature-request.yml
│ └── support-question.yml
├── actions
│ ├── badge
│ │ ├── action.yml
│ │ ├── publish
│ │ │ └── action.yml
│ │ └── write
│ │ │ └── action.yml
│ ├── install
│ │ ├── boost-json
│ │ │ └── action.yml
│ │ ├── cmake
│ │ │ └── action.yml
│ │ ├── danielaparker-jsoncons
│ │ │ └── action.yml
│ │ ├── gtest
│ │ │ └── action.yml
│ │ ├── kazuho-picojson
│ │ │ └── action.yml
│ │ ├── libressl
│ │ │ └── action.yml
│ │ ├── nlohmann-json
│ │ │ └── action.yml
│ │ ├── open-source-parsers-jsoncpp
│ │ │ └── action.yml
│ │ ├── openssl
│ │ │ └── action.yml
│ │ └── wolfssl
│ │ │ └── action.yml
│ ├── process-linting-results
│ │ └── action.yml
│ └── render
│ │ ├── defaults
│ │ └── action.yml
│ │ └── tests
│ │ └── action.yml
├── logo.svg
├── security.md
└── workflows
│ ├── cmake.yml
│ ├── cross-platform.yml
│ ├── documentation.yml
│ ├── jwt.yml
│ ├── lint.yml
│ ├── release.yml
│ ├── ssl.yml
│ ├── targets.yml
│ └── traits.yml
├── .gitignore
├── .vscode
└── extensions.json
├── CMakeLists.txt
├── CMakePresets.json
├── LICENSE
├── README.md
├── cmake
├── CMakePresets.json
├── HunterGate.cmake
├── code-coverage.cmake
├── jwt-cpp-config.cmake.in
├── private-find-boost-json.cmake
└── private-find-kazuho-picojson.cmake
├── docs
├── .gitignore
├── CMakeLists.txt
├── Doxyfile
├── faqs.md
├── install.md
├── overrides.css
├── signing.md
├── ssl.md
└── traits.md
├── example
├── CMakeLists.txt
├── CMakePresets.json
├── es256k.cpp
├── jwks-verify.cpp
├── partial-claim-verifier.cpp
├── print-claims.cpp
├── private-claims.cpp
├── rsa-create.cpp
├── rsa-verify.cpp
└── traits
│ ├── CMakeLists.txt
│ ├── README.md
│ ├── boost-json.cpp
│ ├── danielaparker-jsoncons.cpp
│ ├── kazuho-picojson.cpp
│ ├── nlohmann-json.cpp
│ └── open-source-parsers-jsoncpp.cpp
├── include
├── jwt-cpp
│ ├── base.h
│ ├── jwt.h
│ └── traits
│ │ ├── boost-json
│ │ ├── defaults.h
│ │ └── traits.h
│ │ ├── danielaparker-jsoncons
│ │ ├── defaults.h
│ │ └── traits.h
│ │ ├── defaults.h.mustache
│ │ ├── kazuho-picojson
│ │ ├── defaults.h
│ │ └── traits.h
│ │ ├── nlohmann-json
│ │ ├── defaults.h
│ │ └── traits.h
│ │ └── open-source-parsers-jsoncpp
│ │ ├── defaults.h
│ │ └── traits.h
└── picojson
│ └── picojson.h
├── nuget
├── jwt-cpp.nuspec
└── jwt-cpp.targets
└── tests
├── BaseTest.cpp
├── CMakeLists.txt
├── CMakePresets.json
├── ClaimTest.cpp
├── HelperTest.cpp
├── JwksTest.cpp
├── Keys.cpp
├── OpenSSLErrorTest.cpp
├── TestMain.cpp
├── TokenFormatTest.cpp
├── TokenTest.cpp
├── cmake
├── CMakeLists.txt
├── base64-is-disabled.cpp
├── defaults-enabled.cpp
├── libressl-is-used.cpp
├── picojson-is-disabled.cpp
└── wolfssl-is-used.cpp
├── fuzz
├── BaseDecodeFuzz.cpp
├── BaseEncodeFuzz.cpp
├── CMakeLists.txt
├── TokenDecodeFuzz.cpp
├── decode-corpus
│ ├── 086a3aa337038cac8a75a05131444f222e48aee8
│ ├── 8ebaef2304e91465585c8d7fcf4d9f939e08d6b4
│ ├── ba528234d9f6949ed9c9626c08a782f6e7c15b8b
│ ├── de1028a3fe87471f027522c3ed9ec02b8364a006
│ └── e8f531caaa67cecb1c7b162f3e1d4e320d79befd
└── token-corpus
│ ├── 9d891e731f75deae56884d79e9816736b7488080
│ ├── ff384e2421a333cd52f259cec14c7f790d595db9
│ └── valid-sample
└── traits
├── BoostJsonTest.cpp
├── JsonconsTest.cpp
├── NlohmannTest.cpp
├── OspJsoncppTest.cpp
└── TraitsTest.cpp.mustache
/.clang-format:
--------------------------------------------------------------------------------
1 | BasedOnStyle: LLVM
2 | BreakBeforeBraces: Attach
3 |
4 | ColumnLimit: 120 # Match GitHub UI
5 |
6 | UseTab: Always
7 | TabWidth: 4
8 | IndentWidth: 4
9 | AccessModifierOffset: -4
10 | ContinuationIndentWidth: 4
11 | NamespaceIndentation: All
12 | IndentCaseLabels: false
13 |
14 | PointerAlignment: Left
15 | AlwaysBreakTemplateDeclarations: Yes
16 | SpaceAfterTemplateKeyword: false
17 | AllowShortCaseLabelsOnASingleLine: true
18 | AllowShortIfStatementsOnASingleLine: WithoutElse
19 | AllowShortBlocksOnASingleLine: Always
20 |
21 | FixNamespaceComments: true
22 | ReflowComments: false
23 |
--------------------------------------------------------------------------------
/.clang-tidy:
--------------------------------------------------------------------------------
1 | Checks: '-*,
2 | bugprone-*,
3 | cert-*,
4 | clang-analyzer-*,
5 | clang-diagnostic-*,
6 | -clang-diagnostic-c++17-extensions,
7 | google-*,
8 | -google-runtime-references,
9 | -google-readability-braces-around-statements,
10 | hicpp-*,
11 | -hicpp-braces-around-statements,
12 | -hicpp-signed-bitwise,
13 | misc-*,
14 | -misc-non-private-member-variables-in-classes,
15 | llvm-*,
16 | modernize-*,
17 | -modernize-use-trailing-return-type,
18 | performance-*,
19 | portability-*,
20 | readability-*,
21 | -readability-magic-numbers,
22 | -readability-braces-around-statements,
23 | -readability-uppercase-literal-suffix,
24 | -misc-include-cleaner'
25 |
26 | CheckOptions:
27 | - key: readability-identifier-naming.TypedefCase
28 | value: lower_case
29 | - key: readability-identifier-naming.StructCase
30 | value: lower_case
31 | - key: readability-identifier-naming.ClassCase
32 | value: lower_case
33 | - key: readability-identifier-naming.VariableCase
34 | value: lower_case
35 | - key: readability-identifier-naming.ParameterCase
36 | value: lower_case
37 | - key: readability-identifier-naming.FunctionCase
38 | value: lower_case
39 | - key: readability-identifier-naming.NamespaceCase
40 | value: lower_case
41 | - key: readability-identifier-naming.GlobalConstantCase
42 | value: lower_case
--------------------------------------------------------------------------------
/.cmake-format:
--------------------------------------------------------------------------------
1 | # ----------------------------------
2 | # Options affecting listfile parsing
3 | # ----------------------------------
4 | with section("parse"):
5 |
6 | # Specify structure for custom cmake functions
7 | additional_commands = { 'foo': { 'flags': ['BAR', 'BAZ'],
8 | 'kwargs': {'DEPENDS': '*', 'HEADERS': '*', 'SOURCES': '*'}}}
9 |
10 | # -----------------------------
11 | # Options effecting formatting.
12 | # -----------------------------
13 | with section("format"):
14 |
15 | # How wide to allow formatted cmake files
16 | line_width = 120
17 |
18 | # How many spaces to tab for indent
19 | tab_size = 2
20 |
21 | # If an argument group contains more than this many sub-groups (parg or kwarg
22 | # groups) then force it to a vertical layout.
23 | max_subgroups_hwrap = 12
24 |
25 | # If a positional argument group contains more than this many arguments, then
26 | # force it to a vertical layout.
27 | max_pargs_hwrap = 24
28 |
29 | # If true, separate flow control names from their parentheses with a space
30 | separate_ctrl_name_with_space = False
31 |
32 | # If true, separate function names from parentheses with a space
33 | separate_fn_name_with_space = False
34 |
35 | # If a statement is wrapped to more than one line, than dangle the closing
36 | # parenthesis on its own line.
37 | dangle_parens = False
38 |
39 | # If the trailing parenthesis must be 'dangled' on its on line, then align it
40 | # to this reference: `prefix`: the start of the statement, `prefix-indent`:
41 | # the start of the statement, plus one indentation level, `child`: align to
42 | # the column of the arguments
43 | dangle_align = 'prefix'
44 |
45 | # If the statement spelling length (including space and parenthesis) is
46 | # smaller than this amount, then force reject nested layouts.
47 | min_prefix_chars = 4
48 |
49 | # If the statement spelling length (including space and parenthesis) is larger
50 | # than the tab width by more than this amount, then force reject un-nested
51 | # layouts.
52 | max_prefix_chars = 10
53 |
54 | # If a candidate layout is wrapped horizontally but it exceeds this many
55 | # lines, then reject the layout.
56 | max_lines_hwrap = 12
57 |
58 | # What style line endings to use in the output.
59 | line_ending = 'unix'
60 |
61 | # Format command names consistently as 'lower' or 'upper' case
62 | command_case = 'lower'
63 |
64 | # Format keywords consistently as 'lower' or 'upper' case
65 | keyword_case = 'upper'
66 |
67 | # A list of command names which should always be wrapped
68 | always_wrap = []
69 |
70 | # If true, the argument lists which are known to be sortable will be sorted
71 | # lexicographicall
72 | enable_sort = True
73 |
74 | # If true, the parsers may infer whether or not an argument list is sortable
75 | # (without annotation).
76 | autosort = False
77 |
78 | # By default, if cmake-format cannot successfully fit everything into the
79 | # desired linewidth it will apply the last, most agressive attempt that it
80 | # made. If this flag is True, however, cmake-format will print error, exit
81 | # with non-zero status code, and write-out nothing
82 | require_valid_layout = False
83 |
84 | # A dictionary mapping layout nodes to a list of wrap decisions. See the
85 | # documentation for more information.
86 | layout_passes = {}
87 |
88 | # ------------------------------------------------
89 | # Options affecting comment reflow and formatting.
90 | # ------------------------------------------------
91 | with section("markup"):
92 |
93 | # What character to use for bulleted lists
94 | bullet_char = '*'
95 |
96 | # What character to use as punctuation after numerals in an enumerated list
97 | enum_char = '.'
98 |
99 | # If comment markup is enabled, don't reflow the first comment block in each
100 | # listfile. Use this to preserve formatting of your copyright/license
101 | # statements.
102 | first_comment_is_literal = False
103 |
104 | # If comment markup is enabled, don't reflow any comment block which matches
105 | # this (regex) pattern. Default is `None` (disabled).
106 | literal_comment_pattern = None
107 |
108 | # Regular expression to match preformat fences in comments
109 | # default=r'^\s*([`~]{3}[`~]*)(.*)$'
110 | fence_pattern = '^\\s*([`~]{3}[`~]*)(.*)$'
111 |
112 | # Regular expression to match rulers in comments
113 | # default=r'^\s*[^\w\s]{3}.*[^\w\s]{3}$'
114 | ruler_pattern = '^\\s*[^\\w\\s]{3}.*[^\\w\\s]{3}$'
115 |
116 | # If a comment line matches starts with this pattern then it is explicitly a
117 | # trailing comment for the preceeding argument. Default is '#<'
118 | explicit_trailing_pattern = '#<'
119 |
120 | # If a comment line starts with at least this many consecutive hash
121 | # characters, then don't lstrip() them off. This allows for lazy hash rulers
122 | # where the first hash char is not separated by space
123 | hashruler_min_length = 10
124 |
125 | # If true, then insert a space between the first hash char and remaining hash
126 | # chars in a hash ruler, and normalize its length to fill the column
127 | canonicalize_hashrulers = True
128 |
129 | # enable comment markup parsing and reflow
130 | enable_markup = True
131 |
132 | # ----------------------------
133 | # Options affecting the linter
134 | # ----------------------------
135 | with section("lint"):
136 |
137 | # a list of lint codes to disable
138 | disabled_codes = []
139 |
140 | # regular expression pattern describing valid function names
141 | function_pattern = '[0-9a-z_]+'
142 |
143 | # regular expression pattern describing valid macro names
144 | macro_pattern = '[0-9A-Z_]+'
145 |
146 | # regular expression pattern describing valid names for variables with global
147 | # scope
148 | global_var_pattern = '[0-9A-Z][0-9A-Z_]+'
149 |
150 | # regular expression pattern describing valid names for variables with global
151 | # scope (but internal semantic)
152 | internal_var_pattern = '_[0-9A-Z][0-9A-Z_]+'
153 |
154 | # regular expression pattern describing valid names for variables with local
155 | # scope
156 | local_var_pattern = '[0-9a-z_]+'
157 |
158 | # regular expression pattern describing valid names for privatedirectory
159 | # variables
160 | private_var_pattern = '_[0-9a-z_]+'
161 |
162 | # regular expression pattern describing valid names for publicdirectory
163 | # variables
164 | public_var_pattern = '[0-9A-Z][0-9A-Z_]+'
165 |
166 | # regular expression pattern describing valid names for keywords used in
167 | # functions or macros
168 | keyword_pattern = '[0-9A-Z_]+'
169 |
170 | # In the heuristic for C0201, how many conditionals to match within a loop in
171 | # before considering the loop a parser.
172 | max_conditionals_custom_parser = 2
173 |
174 | # Require at least this many newlines between statements
175 | min_statement_spacing = 1
176 |
177 | # Require no more than this many newlines between statements
178 | max_statement_spacing = 1
179 | max_returns = 6
180 | max_branches = 12
181 | max_arguments = 5
182 | max_localvars = 15
183 | max_statements = 50
184 |
185 | # -------------------------------
186 | # Options effecting file encoding
187 | # -------------------------------
188 | with section("encode"):
189 |
190 | # If true, emit the unicode byte-order mark (BOM) at the start of the file
191 | emit_byteorder_mark = False
192 |
193 | # Specify the encoding of the input file. Defaults to utf-8
194 | input_encoding = 'utf-8'
195 |
196 | # Specify the encoding of the output file. Defaults to utf-8. Note that cmake
197 | # only claims to support utf-8 so be careful when using anything else
198 | output_encoding = 'utf-8'
199 |
200 | # -------------------------------------
201 | # Miscellaneous configurations options.
202 | # -------------------------------------
203 | with section("misc"):
204 |
205 | # A dictionary containing any per-command configuration overrides. Currently
206 | # only `command_case` is supported.
207 | per_command = {}
208 |
209 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [!*.{h,cpp}]
4 | indent_style = space
5 | indent_size = 2
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
11 | [*.{h,cpp}]
12 | indent_style = tab
13 | trim_trailing_whitespace = true
14 | insert_final_newline = true
15 |
16 | [*.md]
17 | trim_trailing_whitespace = false
18 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [Thalhammer,prince-chrismc]
2 | patreon: Thalhammer
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report 🐛
2 | description: File a bug report
3 |
4 | labels: ["bug"]
5 | body:
6 | - type: markdown
7 | attributes:
8 | value: |
9 | Thanks for taking the time to fill out this bug report!
10 | validations:
11 | required: false
12 | - type: textarea
13 | id: what-happened
14 | attributes:
15 | label: What happened?
16 | description: Also tell us, what did you expect to happen? Feel free to include some screenshots
17 | placeholder: Tell us what you see!
18 | value: "A bug happened!"
19 | validations:
20 | required: true
21 | - type: textarea
22 | id: reproduce
23 | attributes:
24 | label: How To Reproduce?
25 | description: Please provide a small snippet to reproduce the issue
26 | placeholder: Some C++ code or Shell code to recreate th problem
27 | value: |
28 | ```c++
29 | #include "jwt-cpp/jwt.h"
30 | int main() {
31 | return 0;
32 | }
33 | ```
34 | - type: dropdown
35 | id: version
36 | attributes:
37 | label: Version
38 | description: What version of our software are you running?
39 | options:
40 | - 0.7.1
41 | - 0.7.0
42 | - 0.6.0
43 | - 0.5.2
44 | - Older (please let us know if the "What happened" box)
45 | validations:
46 | required: true
47 | - type: dropdown
48 | id: operating-system
49 | attributes:
50 | label: What OS are you seeing the problem on?
51 | multiple: true
52 | options:
53 | - Windows
54 | - Linux
55 | - MacOS
56 | - Other (please let us know if the "What happened" box)
57 | validations:
58 | required: true
59 | - type: dropdown
60 | id: compiler
61 | attributes:
62 | label: What compiler are you seeing the problem on?
63 | multiple: true
64 | options:
65 | - GCC
66 | - Clang
67 | - MSVC
68 | - Other (please let us know if the "What happened" box)
69 | validations:
70 | required: true
71 | - type: textarea
72 | id: logs
73 | attributes:
74 | label: Relevant log output
75 | description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
76 | render: shell
77 | - type: checkboxes
78 | id: terms
79 | attributes:
80 | label: Code of Conduct
81 | description: By submitting this issue, you agree to follow our [Code of Conduct](https://example.com)
82 | options:
83 | - label: I agree to follow this project's Code of Conduct
84 | required: true
85 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.yml:
--------------------------------------------------------------------------------
1 | name: Feature Request 🧪
2 | description: Have a great idea? Find something is missing?
3 | labels: ["enhancement"]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | We'd love to hear your idea(s)!
9 | - type: input
10 | id: question
11 | attributes:
12 | label: "What would you like to see added?"
13 | validations:
14 | required: true
15 | - type: textarea
16 | id: context
17 | attributes:
18 | label: Additional Context
19 | validations:
20 | required: true
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/support-question.yml:
--------------------------------------------------------------------------------
1 | name: Support Question 🤹
2 | description: Have some questions? We can offer help.
3 | labels: ["question"]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Don't hesitate to ask any question you might have!
9 | - type: input
10 | id: question
11 | attributes:
12 | label: "What's your question?"
13 | validations:
14 | required: true
15 | - type: textarea
16 | id: context
17 | attributes:
18 | label: Additional Context
19 | validations:
20 | required: true
21 |
--------------------------------------------------------------------------------
/.github/actions/badge/action.yml:
--------------------------------------------------------------------------------
1 | name: Regular badging sequence
2 | description: Publishes a badge based on the job status
3 | inputs:
4 | category:
5 | description: The subfolder where to group the badges
6 | required: true
7 | label:
8 | description: The label to you in the badge (this should be unique for each badge in a category)
9 | required: true
10 | github_token:
11 | description: The token to use to publish the changes
12 | required: false
13 | default: ${{ github.token }}
14 | runs:
15 | using: composite
16 | steps:
17 | - if: job.status == 'success'
18 | uses: ./.github/actions/badge/write
19 | with:
20 | category: ${{ inputs.category }}
21 | label: ${{ inputs.label }}
22 | - if: job.status == 'failure'
23 | uses: ./.github/actions/badge/write
24 | with:
25 | category: ${{ inputs.category }}
26 | label: ${{ inputs.label }}
27 | message: Failing
28 | color: red
29 | - uses: ./.github/actions/badge/publish
30 | with:
31 | github_token: ${{ inputs.github_token }}
32 |
--------------------------------------------------------------------------------
/.github/actions/badge/publish/action.yml:
--------------------------------------------------------------------------------
1 | name: Publish a Badges
2 | description: Publishes all badges
3 | inputs:
4 | github_token:
5 | description: The token to use to publish the changes
6 | required: false
7 | default: ${{ github.token }}
8 | runs:
9 | using: composite
10 | steps:
11 | - uses: peaceiris/actions-gh-pages@v3
12 | with:
13 | github_token: ${{ inputs.github_token }}
14 | publish_branch: badges
15 | publish_dir: ./badges
16 | keep_files: true
17 | user_name: "github-actions[bot]"
18 | user_email: "github-actions[bot]@users.noreply.github.com"
19 |
--------------------------------------------------------------------------------
/.github/actions/badge/write/action.yml:
--------------------------------------------------------------------------------
1 | name: Make a Badge
2 | description: Creates a JSON file for use with Sheilds.io. The default is a "brightgreen" "Passing" badge
3 | inputs:
4 | category:
5 | description: The subfolder where to group the badges
6 | required: true
7 | label:
8 | description: The label to you in the badge (this should be unqie for each badge in a category)
9 | required: true
10 | message:
11 | description: The message you wish to have in the badge
12 | required: false
13 | default: "Passing"
14 | color:
15 | description: The color you wish the badge to be
16 | required: false
17 | default: "brightgreen"
18 | runs:
19 | using: composite
20 | steps:
21 | - run: |
22 | mkdir -p badges/${{ inputs.category }}/${{ inputs.label }}
23 | echo '{ "schemaVersion": 1, "label": "${{ inputs.label }}", "message": "${{ inputs.message }}", "color": "${{ inputs.color }}" }' > badges/${{ inputs.category }}/${{ inputs.label }}/shields.json
24 | shell: bash
25 |
--------------------------------------------------------------------------------
/.github/actions/install/boost-json/action.yml:
--------------------------------------------------------------------------------
1 | name: Install Boost.JSON
2 | description: Install Boost.JSON for building test application
3 | inputs:
4 | version:
5 | description: The desired Boost.JSON version to install
6 | required: false
7 | default: "1.78.0"
8 | runs:
9 | using: composite
10 | steps:
11 | - run: |
12 | cd /tmp
13 | wget https://github.com/boostorg/json/archive/boost-${{ inputs.version }}.tar.gz
14 | tar -zxf /tmp/boost-${{ inputs.version }}.tar.gz
15 | cd json-boost-${{ inputs.version }}
16 | sudo cp -vR include/boost /usr/local/include
17 | shell: bash
18 |
--------------------------------------------------------------------------------
/.github/actions/install/cmake/action.yml:
--------------------------------------------------------------------------------
1 | name: Install CMake
2 | description: Download, Build and Cache CMake
3 | inputs:
4 | version:
5 | description: The desired CMake version to install
6 | required: true
7 | url:
8 | description: "The corresponding URL to download the source code from"
9 | required: true
10 | runs:
11 | using: composite
12 | steps:
13 | - name: Cache CMake
14 | id: cache-cmake
15 | uses: actions/cache@v4
16 | with:
17 | path: cmake-${{ inputs.version }}
18 | key: ${{ runner.name }}-${{ runner.os }}-${{ runner.arch }}-${{ job.container.id }}-cmake-${{ inputs.version }}
19 | - name: Build cmake
20 | if: steps.cache-cmake.outputs.cache-hit != 'true'
21 | run: |
22 | wget ${{ inputs.url }}
23 | tar -zxf cmake-${{ inputs.version }}.tar.gz
24 | cd cmake-${{ inputs.version }}
25 | ./bootstrap
26 | make -j $(nproc)
27 | shell: bash
28 | - name: Install cmake
29 | run: |
30 | cd cmake-${{ inputs.version }}
31 | # Depending if we run in on a GitHub Actions or from within a Docker image we have different permissions
32 | if [[ $EUID > 0 ]]; then
33 | # If we are not root then we need to sudo
34 | sudo make install
35 | else
36 | # Default docker image does not have users setup so we are only root and can not sudo
37 | make install
38 | fi
39 | shell: bash
40 |
--------------------------------------------------------------------------------
/.github/actions/install/danielaparker-jsoncons/action.yml:
--------------------------------------------------------------------------------
1 | name: Install jsoncons
2 | description: Install jsoncons for building test application
3 | inputs:
4 | version:
5 | description: The desired jsoncons version to install
6 | required: false
7 | default: "1.3.2"
8 | runs:
9 | using: composite
10 | steps:
11 | - run: |
12 | cd /tmp
13 | wget https://github.com/danielaparker/jsoncons/archive/v${{ inputs.version }}.tar.gz
14 | tar -zxf /tmp/v${{ inputs.version }}.tar.gz
15 | cd jsoncons-${{ inputs.version }}
16 | cmake .
17 | sudo cmake --install .
18 | shell: bash
19 |
--------------------------------------------------------------------------------
/.github/actions/install/gtest/action.yml:
--------------------------------------------------------------------------------
1 | name: Install GTest
2 | description: Install and setup GTest for linking and building test application
3 | runs:
4 | using: composite
5 | steps:
6 | - run: sudo apt-get install libgtest-dev lcov
7 | shell: bash
8 | - run: (cd /usr/src/gtest && sudo `which cmake` .)
9 | shell: bash
10 | - run: sudo make -j $(nproc) -C /usr/src/gtest
11 | shell: bash
12 | - run: sudo ln -s /usr/src/gtest/libgtest.a /usr/lib/libgtest.a
13 | shell: bash
14 | - run: sudo ln -s /usr/src/gtest/libgtest_main.a /usr/lib/libgtest_main.a
15 | shell: bash
16 |
--------------------------------------------------------------------------------
/.github/actions/install/kazuho-picojson/action.yml:
--------------------------------------------------------------------------------
1 | name: Install PicoJSON
2 | description: Install PicoJSON for building test application
3 | inputs:
4 | version:
5 | description: The desired PicoJSON version to install
6 | required: false
7 | default: "v1.3.0"
8 | runs:
9 | using: composite
10 | steps:
11 | - run: |
12 | cd /tmp
13 | wget https://github.com/kazuho/picojson/archive/${{ inputs.version }}.tar.gz
14 | tar -zxf /tmp/${{ inputs.version }}.tar.gz
15 | cd picojson-${{ inputs.version }}
16 | sudo cp -v picojson.h /usr/local/include/picojson
17 | shell: bash
18 |
--------------------------------------------------------------------------------
/.github/actions/install/libressl/action.yml:
--------------------------------------------------------------------------------
1 | name: Install LibreSSL
2 | description: Install and setup LibreSSL for linking and building test application
3 | inputs:
4 | version:
5 | description: The desired LibreSSL version to install
6 | required: false
7 | default: "3.3.0"
8 | runs:
9 | using: composite
10 | steps:
11 | - run: |
12 | wget https://raw.githubusercontent.com/libressl-portable/portable/v${{ inputs.version }}/FindLibreSSL.cmake -P cmake/
13 | cd /tmp
14 | wget https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${{ inputs.version }}.tar.gz
15 | tar -zvxf /tmp/libressl-${{ inputs.version }}.tar.gz
16 | cd libressl-${{ inputs.version }}
17 | ./configure
18 | sudo make -j $(nproc) install
19 | shell: bash
20 |
--------------------------------------------------------------------------------
/.github/actions/install/nlohmann-json/action.yml:
--------------------------------------------------------------------------------
1 | name: Install nlohmann-json
2 | description: Install nlohmann-json for building test application
3 | inputs:
4 | version:
5 | description: The desired nlohmann-json version to install
6 | required: false
7 | default: "3.12.0"
8 | runs:
9 | using: composite
10 | steps:
11 | - run: |
12 | cd /tmp
13 | wget https://github.com/nlohmann/json/archive/v${{ inputs.version }}.tar.gz
14 | tar -zxf /tmp/v${{ inputs.version }}.tar.gz
15 | cd json-${{ inputs.version }}
16 | cmake .
17 | sudo cmake --install .
18 | shell: bash
19 |
--------------------------------------------------------------------------------
/.github/actions/install/open-source-parsers-jsoncpp/action.yml:
--------------------------------------------------------------------------------
1 | name: Install open-source-parsers/jsoncpp
2 | description: Install open-source-parsers/jsoncpp for building test application
3 | inputs:
4 | version:
5 | description: The desired open-source-parsers/jsoncpp version to install
6 | required: false
7 | default: "1.9.6"
8 | runs:
9 | using: composite
10 | steps:
11 | - run: |
12 | cd /tmp
13 | wget https://github.com/open-source-parsers/jsoncpp/archive/${{ inputs.version }}.tar.gz
14 | tar -zxf /tmp/${{ inputs.version }}.tar.gz
15 | cd jsoncpp-${{ inputs.version }}
16 | # https://github.com/open-source-parsers/jsoncpp/blob/69098a18b9af0c47549d9a271c054d13ca92b006/include/PreventInSourceBuilds.cmake#L8
17 | mkdir build
18 | cd build
19 | cmake .. -DJSONCPP_WITH_TESTS=OFF -DBUILD_SHARED_LIBS=OFF -DBUILD_OBJECT_LIBS=OFF
20 | cmake --build .
21 | sudo cmake --install .
22 | shell: bash
23 |
--------------------------------------------------------------------------------
/.github/actions/install/openssl/action.yml:
--------------------------------------------------------------------------------
1 | name: Install OpenSSL
2 | description: Install and setup OpenSSL for linking and building test application
3 | inputs:
4 | version:
5 | description: The desired OpenSSL version to install
6 | required: false
7 | default: "openssl-3.0.0"
8 | runs:
9 | using: composite
10 | steps:
11 | - run: |
12 | cd /tmp
13 | wget https://github.com/openssl/openssl/archive/refs/tags/${{ inputs.version }}.tar.gz
14 | tar -zxf /tmp/${{ inputs.version }}.tar.gz
15 | cd openssl-${{ inputs.version }}
16 | ./config --prefix=/tmp --libdir=lib
17 | make -j $(nproc)
18 | sudo make -j $(nproc) install_sw
19 | echo "OPENSSL_ROOT_DIR=/tmp" >> "$GITHUB_ENV"
20 | echo "OpenSSL_ROOT=/tmp" >> "$GITHUB_ENV"
21 | shell: bash
22 |
--------------------------------------------------------------------------------
/.github/actions/install/wolfssl/action.yml:
--------------------------------------------------------------------------------
1 | name: Install wolfSSL
2 | description: Install and setup wolfSSL for linking and building test application
3 | inputs:
4 | version:
5 | description: The desired stable wolfSSL version to install
6 | required: false
7 | default: "v4.8.1-stable"
8 | runs:
9 | using: composite
10 | steps:
11 | - run: |
12 | cd /tmp
13 | wget -O wolfssl.tar.gz https://github.com/wolfSSL/wolfssl/archive/${{ inputs.version }}.tar.gz
14 | tar -zxf /tmp/wolfssl.tar.gz
15 | cd wolfssl-*
16 | autoreconf -fiv
17 | ./configure --enable-opensslall --enable-opensslextra --disable-examples --disable-crypttests --enable-harden --enable-all --enable-all-crypto
18 | make
19 | sudo make install
20 | shell: bash
21 | - run: sudo rm -rf /usr/include/openssl
22 | shell: bash
23 |
--------------------------------------------------------------------------------
/.github/actions/process-linting-results/action.yml:
--------------------------------------------------------------------------------
1 | name: Process Linting Results
2 | description: Add a comment to a pull request with when `git diff` present and save the changes as an artifact so they can be applied manually
3 | inputs:
4 | linter_name:
5 | description: The name of the tool to credit in the comment
6 | required: true
7 | runs:
8 | using: "composite"
9 | steps:
10 | - run: git add --update
11 | shell: bash
12 | - id: stage
13 | #continue-on-error: true
14 | uses: Thalhammer/patch-generator-action@v3
15 |
16 | # Unfortunately the previous action reports a failure so nothing else can run
17 | # partially a limitation on composite actions since `continue-on-error` is not
18 | # yet supported
19 | - if: steps.stage.outputs.result == 'dirty'
20 | uses: actions-ecosystem/action-create-comment@v1
21 | with:
22 | github_token: ${{ github.token }}
23 | body: |
24 | Hello, @${{ github.actor }}! `${{ inputs.linter_name }}` had some concerns :scream:
25 | - run: exit $(git status -uno -s | wc -l)
26 | shell: bash
27 |
--------------------------------------------------------------------------------
/.github/actions/render/defaults/action.yml:
--------------------------------------------------------------------------------
1 | name: "Render `defaults.h` Template"
2 | description: "Generate the `defaults.h` header file for a JSON library"
3 | inputs:
4 | traits_name:
5 | description: "Name of the traits structure to be used. Typically in the format `author_repository` or equivilant"
6 | required: true
7 | library_name:
8 | description: "Name of the JSON library."
9 | required: true
10 | library_url:
11 | description: "URL to the JSON library."
12 | required: true
13 | disable_default_traits:
14 | description: "Set the macro to disable the default traits"
15 | required: false
16 | default: "true"
17 | outputs:
18 | file_path:
19 | description: "Relative path which the 'defaults.h' was written to"
20 | value: ${{ steps.script.outputs.result }}
21 | runs:
22 | using: composite
23 | steps:
24 | - uses: actions/setup-node@v3
25 | with:
26 | node-version: 14
27 | - run: npm install mustache
28 | shell: bash
29 | - uses: actions/github-script@v6
30 | id: script
31 | env:
32 | TRAITS_NAME: ${{ inputs.traits_name }}
33 | LIBRARY_NAME: ${{ inputs.library_name }}
34 | LIBRARY_URL: ${{ inputs.library_url }}
35 | DISABLE_DEFAULT_TRAITS: ${{ inputs.disable_default_traits }}
36 | with:
37 | result-encoding: string
38 | script: |
39 | const mustache = require('mustache')
40 | const path = require('path')
41 | const fs = require('fs')
42 |
43 | const { TRAITS_NAME, LIBRARY_NAME, LIBRARY_URL, DISABLE_DEFAULT_TRAITS } = process.env
44 | console.log(`Rendering ${TRAITS_NAME}!`)
45 |
46 | const disableDefault = DISABLE_DEFAULT_TRAITS === 'true'
47 |
48 | const template = fs.readFileSync(path.join('include', 'jwt-cpp', 'traits', 'defaults.h.mustache'), 'utf8')
49 | const content = mustache.render(template, {
50 | traits_name: TRAITS_NAME,
51 | traits_name_upper: TRAITS_NAME.toUpperCase(),
52 | library_name: LIBRARY_NAME,
53 | library_url: LIBRARY_URL,
54 | disable_default_traits: disableDefault,
55 | })
56 | // https://dmitripavlutin.com/replace-all-string-occurrences-javascript/
57 | function replaceAll(string, search, replace) {
58 | return string.split(search).join(replace);
59 | }
60 |
61 | const outputDir = path.join('include', 'jwt-cpp', 'traits', replaceAll(TRAITS_NAME, '_', '-'))
62 | fs.mkdirSync(outputDir, { recursive: true })
63 |
64 | const filePath = path.join(outputDir, 'defaults.h')
65 | fs.writeFileSync(filePath, content)
66 |
67 | return filePath
68 |
--------------------------------------------------------------------------------
/.github/actions/render/tests/action.yml:
--------------------------------------------------------------------------------
1 | name: "Render `TraitsTests.cpp` Template"
2 | description: "Generate the `TraitsTests.cpp` header file for a JSON library"
3 | inputs:
4 | traits_name:
5 | description: "Name of the traits structure to be used. Typically in the format `author_repository` or equivilant"
6 | required: true
7 | test_suite_name:
8 | description: "Name of the JSON library."
9 | required: true
10 | runs:
11 | using: composite
12 | steps:
13 | - uses: actions/setup-node@v3
14 | with:
15 | node-version: 14
16 | - run: npm install mustache
17 | shell: bash
18 | - uses: actions/github-script@v6
19 | env:
20 | TRAITS_NAME: ${{ inputs.traits_name }}
21 | SUITE_NAME: ${{ inputs.test_suite_name }}
22 | with:
23 | script: |
24 | const mustache = require('mustache')
25 | const path = require('path')
26 | const fs = require('fs')
27 |
28 | const { TRAITS_NAME, SUITE_NAME } = process.env
29 | console.log(`Rendering ${TRAITS_NAME}!`)
30 |
31 | // https://dmitripavlutin.com/replace-all-string-occurrences-javascript/
32 | function replaceAll(string, search, replace) {
33 | return string.split(search).join(replace);
34 | }
35 |
36 | const template = fs.readFileSync(path.join('tests', 'traits', 'TraitsTest.cpp.mustache'), 'utf8')
37 | const content = mustache.render(template, {
38 | traits_name: TRAITS_NAME,
39 | traits_dir: replaceAll(TRAITS_NAME, '_', '-'),
40 | test_suite_name: SUITE_NAME,
41 | })
42 | const outputDir = path.join('tests', 'traits')
43 | fs.mkdirSync(outputDir, { recursive: true })
44 | fs.writeFileSync(path.join(outputDir, `${SUITE_NAME}.cpp`), content)
45 |
--------------------------------------------------------------------------------
/.github/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.github/security.md:
--------------------------------------------------------------------------------
1 | # Reporting Security Issues
2 |
3 | If you believe you have found a security vulnerability in JWT-CPP, we encourage you to let us know right away.
4 | We will investigate all legitimate reports and do our best to quickly fix the problem.
5 |
6 | Please refer to the section below for our responsible disclosure policy:
7 |
8 | ## Disclosure Policy
9 |
10 | Please contact one or more of the maintainers using the email advertised on our GitHub profiles:
11 |
12 | - [@Thalhammer](https://github.com/Thalhammer)
13 | - [@prince-chrismc](https://github.com/prince-chrismc)
14 |
15 | Please provide as many details as possible about version, platform, and workflow as possible.
16 | Having steps and reproducible code is better and is always greatly appreciated.
17 |
18 | ## Supported Version
19 |
20 | Typically, fixes will be immediately released as a new patch release. However, older affected versions may receive
21 | a new patch upon request.
22 |
--------------------------------------------------------------------------------
/.github/workflows/cross-platform.yml:
--------------------------------------------------------------------------------
1 | name: Cross-Platform CI
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | pull_request:
7 | branches: [master]
8 | jobs:
9 | build:
10 | runs-on: ${{ matrix.os }}
11 | strategy:
12 | matrix:
13 | os: [macos-latest, windows-latest, ubuntu-latest]
14 |
15 | steps:
16 | - uses: actions/checkout@v4
17 |
18 | - name: configure
19 | run: cmake --preset examples
20 |
21 | - name: build
22 | run: cmake --build --preset examples
23 |
24 | - name: test
25 | run: |
26 | cmake --build --preset examples --target rsa-create-run
27 | cmake --build --preset examples --target rsa-verify-run
28 |
29 | - if: github.event_name == 'push' && always()
30 | uses: ./.github/actions/badge
31 | with:
32 | category: cross-platform
33 | label: ${{ matrix.os }}
34 |
--------------------------------------------------------------------------------
/.github/workflows/documentation.yml:
--------------------------------------------------------------------------------
1 | name: Documentation CI
2 |
3 | on:
4 | push:
5 | branches: [master]
6 |
7 | jobs:
8 | build:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v4
12 | - uses: ssciwr/doxygen-install@v1
13 | with:
14 | version: "1.10.0"
15 | - run: sudo apt install graphviz
16 | - run: |
17 | cmake . -DJWT_BUILD_DOCS=ON
18 | cmake --build . --target jwt-docs
19 | - if: github.event_name == 'push'
20 | name: deploy
21 | uses: peaceiris/actions-gh-pages@v3
22 | with:
23 | github_token: ${{ secrets.GITHUB_TOKEN }}
24 | publish_dir: ./build/html
25 | force_orphan: true
26 |
--------------------------------------------------------------------------------
/.github/workflows/jwt.yml:
--------------------------------------------------------------------------------
1 | name: JWT CI
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | pull_request:
7 | branches: [master]
8 |
9 | jobs:
10 | coverage:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v4
14 | - uses: lukka/get-cmake@latest
15 | - uses: ./.github/actions/install/gtest
16 | - uses: ./.github/actions/install/danielaparker-jsoncons
17 | - uses: ./.github/actions/install/boost-json
18 | - uses: ./.github/actions/install/open-source-parsers-jsoncpp
19 |
20 | - name: configure
21 | run: cmake --preset coverage
22 | - name: run
23 | run: cmake --build --preset coverage
24 |
25 | - uses: coverallsapp/github-action@v2
26 | with:
27 | github-token: ${{ secrets.GITHUB_TOKEN }}
28 | file: build/coverage.info
29 | format: lcov
30 |
31 | fuzzing:
32 | runs-on: ubuntu-latest
33 | steps:
34 | - uses: actions/checkout@v4
35 | - uses: lukka/get-cmake@latest
36 |
37 | - name: configure
38 | run: cmake --preset ci-fuzzing
39 | - name: build
40 | run: cmake --build --preset ci-fuzzing
41 |
42 | - name: run
43 | run: |
44 | cmake --build --preset ci-fuzzing --target jwt-cpp-fuzz-BaseEncodeFuzz-run
45 | cmake --build --preset ci-fuzzing --target jwt-cpp-fuzz-BaseDecodeFuzz-run
46 | cmake --build --preset ci-fuzzing --target jwt-cpp-fuzz-TokenDecodeFuzz-run
47 |
48 | asan:
49 | runs-on: ubuntu-latest
50 | strategy:
51 | fail-fast: false
52 | matrix:
53 | openssl:
54 | - { tag: "openssl-3.0.5", name: "3.0.5" }
55 | - { tag: "OpenSSL_1_1_1q", name: "1.1.1q" }
56 | steps:
57 | - uses: actions/checkout@v4
58 | - uses: lukka/get-cmake@latest
59 | - uses: ./.github/actions/install/gtest
60 | - uses: ./.github/actions/install/openssl
61 | with:
62 | version: ${{ matrix.openssl.tag }}
63 |
64 | - name: configure
65 | run: cmake --preset ci-asan
66 | - name: build
67 | run: cmake --build --preset ci-asan
68 |
69 | - name: run
70 | run: |
71 | cmake --build --preset ci-asan --target private-claims-run
72 | cmake --build --preset ci-asan --target rsa-create-run
73 | cmake --build --preset ci-asan --target rsa-verify-run
74 | cmake --build --preset ci-asan --target jwks-verify-run
75 | cmake --build --preset ci-asan --target jwt-cpp-test-run
76 |
77 | ubsan:
78 | runs-on: ubuntu-latest
79 | steps:
80 | - uses: actions/checkout@v4
81 | - uses: lukka/get-cmake@latest
82 | - uses: ./.github/actions/install/gtest
83 |
84 | - name: configure
85 | run: cmake --preset ci-ubsan
86 | - name: build
87 | run: cmake --build --preset ci-ubsan -DCMAKE_CXX_STANDARD=20
88 |
89 | - name: run
90 | run: |
91 | cmake --build --preset ci-ubsan --target private-claims-run
92 | cmake --build --preset ci-ubsan --target rsa-create-run
93 | cmake --build --preset ci-ubsan --target rsa-verify-run
94 | cmake --build --preset ci-ubsan --target jwks-verify-run
95 | cmake --build --preset ci-ubsan --target jwt-cpp-test-run
96 |
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | name: Lint CI
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | pull_request:
7 | branches: [master]
8 |
9 | jobs:
10 | clang-format:
11 | runs-on: ubuntu-22.04
12 | strategy:
13 | fail-fast: false
14 | matrix:
15 | files:
16 | - "include/jwt-cpp/*.h"
17 | - "include/jwt-cpp/traits/**/*.h"
18 | - "tests/*.cpp"
19 | - "tests/**/*.cpp"
20 | - "example/*.cpp"
21 | - "example/**/*.cpp"
22 | steps:
23 | - run: |
24 | sudo apt-get install clang-format-14
25 | shopt -s globstar
26 | - uses: actions/checkout@v4
27 | - run: clang-format-14 -i ${{ matrix.files }}
28 | - uses: ./.github/actions/process-linting-results
29 | with:
30 | linter_name: clang-format
31 |
32 | cmake-format:
33 | runs-on: ubuntu-latest
34 | strategy:
35 | fail-fast: false
36 | matrix:
37 | files: ["**/CMakeLists.txt", "cmake/code-coverage.cmake"]
38 | steps:
39 | - uses: actions/setup-python@v5
40 | with:
41 | python-version: "3.x"
42 | - run: pip install cmakelang
43 | - run: shopt -s globstar
44 | - uses: actions/checkout@v4
45 | - run: cmake-format -i ${{ matrix.files }}
46 | - uses: ./.github/actions/process-linting-results
47 | with:
48 | linter_name: cmake-format
49 |
50 | clang-tidy:
51 | runs-on: ubuntu-latest
52 | steps:
53 | - uses: lukka/get-cmake@latest
54 | - uses: actions/checkout@v4
55 | - name: configure
56 | run: cmake --preset examples -DCMAKE_CXX_CLANG_TIDY="clang-tidy;-fix"
57 | - name: run
58 | run: cmake --build --preset examples
59 | - uses: ./.github/actions/process-linting-results
60 | with:
61 | linter_name: clang-tidy
62 |
63 | render-defaults:
64 | runs-on: ubuntu-22.04
65 | strategy:
66 | fail-fast: false
67 | matrix:
68 | traits:
69 | - { name: "boost_json", library: "Boost.JSON", url: "https://github.com/boostorg/json", disable_pico: true }
70 | - { name: "danielaparker_jsoncons", library: "jsoncons", url: "https://github.com/danielaparker/jsoncons", disable_pico: true }
71 | - { name: "kazuho_picojson", library: "picojson", url: "https://github.com/kazuho/picojson", disable_pico: false }
72 | - { name: "nlohmann_json", library: "JSON for Modern C++", url: "https://github.com/nlohmann/json", disable_pico: true }
73 | - { name: "open_source_parsers_jsoncpp", library: "jsoncpp", url: "https://github.com/open-source-parsers/jsoncpp", disable_pico: true }
74 | name: render-defaults (${{ matrix.traits.name }})
75 | steps:
76 | - uses: actions/checkout@v4
77 | - run: |
78 | sudo apt-get install clang-format-14
79 | - uses: ./.github/actions/render/defaults
80 | id: render
81 | with:
82 | traits_name: ${{ matrix.traits.name }}
83 | library_name: ${{ matrix.traits.library }}
84 | library_url: ${{ matrix.traits.url }}
85 | disable_default_traits: ${{ matrix.traits.disable_pico }}
86 | - run: clang-format-14 -i ${{ steps.render.outputs.file_path }}
87 | - run: git add ${{ steps.render.outputs.file_path }}
88 | - uses: ./.github/actions/process-linting-results
89 | with:
90 | linter_name: render-defaults
91 |
92 | render-tests:
93 | runs-on: ubuntu-22.04
94 | strategy:
95 | fail-fast: false
96 | matrix:
97 | traits:
98 | # - { name: "boost_json", suite: "BoostJsonTest" } # Currently needs work arounds for API limitations
99 | - { name: "danielaparker_jsoncons", suite: "JsonconsTest" }
100 | # - { name: "kazuho_picojson", suite: "PicoJsonTest" } # Currently the default everything tests against this!
101 | - { name: "nlohmann_json", suite: "NlohmannTest" }
102 | - { name: "open_source_parsers_jsoncpp", suite: "OspJsoncppTest" }
103 | name: render-tests (${{ matrix.traits.name }})
104 | steps:
105 | - uses: actions/checkout@v4
106 | - run: |
107 | sudo apt-get install clang-format-14
108 | shopt -s globstar
109 | - uses: ./.github/actions/render/tests
110 | with:
111 | traits_name: ${{ matrix.traits.name }}
112 | test_suite_name: ${{ matrix.traits.suite }}
113 | - run: clang-format-14 -i tests/**/*.cpp
114 | - run: git add tests/traits/*
115 | - uses: ./.github/actions/process-linting-results
116 | with:
117 | linter_name: render-tests
118 |
119 | line-ending:
120 | runs-on: ubuntu-latest
121 | steps:
122 | - uses: actions/checkout@v4
123 | - run: git add --renormalize .
124 | - uses: ./.github/actions/process-linting-results
125 | with:
126 | linter_name: line-ending
127 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release CD
2 |
3 | on:
4 | # Allows you to run this workflow manually from the Actions tab
5 | workflow_dispatch:
6 | # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#release
7 | release:
8 | types: [published]
9 |
10 | jobs:
11 | nuget:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v4
15 | - name: Setup NuGet
16 | uses: NuGet/setup-nuget@v1
17 | with:
18 | nuget-api-key: ${{ secrets.nuget_api_key }}
19 |
20 | - name: Create NuGet pkg
21 | working-directory: ./nuget
22 | run: nuget pack jwt-cpp.nuspec
23 |
24 | - name: Publish NuGet pkg
25 | working-directory: ./nuget
26 | run: nuget push *.nupkg -Source 'https://api.nuget.org/v3/index.json'
27 |
28 | release-asset:
29 | if: github.event_name != 'workflow_dispatch'
30 | runs-on: ubuntu-latest
31 | steps:
32 | - uses: actions/checkout@v4
33 |
34 | - run: tar --exclude='./.git' -vczf /tmp/jwt-cpp-${{ github.event.release.tag_name }}.tar.gz .
35 | - uses: shogo82148/actions-upload-release-asset@v1
36 | with:
37 | upload_url: ${{ github.event.release.upload_url }}
38 | asset_path: /tmp/jwt-cpp-${{ github.event.release.tag_name }}.tar.gz
39 |
40 | - run: zip -x './.git/*' -r /tmp/jwt-cpp-${{ github.event.release.tag_name }}.zip .
41 | - uses: shogo82148/actions-upload-release-asset@v1
42 | with:
43 | upload_url: ${{ github.event.release.upload_url }}
44 | asset_path: /tmp/jwt-cpp-${{ github.event.release.tag_name }}.zip
45 |
--------------------------------------------------------------------------------
/.github/workflows/ssl.yml:
--------------------------------------------------------------------------------
1 | name: SSL Compatibility CI
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | pull_request:
7 | branches: [master]
8 |
9 | jobs:
10 | openssl:
11 | runs-on: ubuntu-latest
12 | strategy:
13 | matrix:
14 | openssl:
15 | - { tag: "openssl-3.0.5", name: "3.0.5" }
16 | - { tag: "OpenSSL_1_1_1q", name: "1.1.1q" }
17 | - { tag: "OpenSSL_1_1_0i", name: "1.1.0i" } # Do not bump, there's a broken in the autoconfig script and it's not maintained
18 | - { tag: "OpenSSL_1_0_2u", name: "1.0.2u" }
19 | - { tag: "OpenSSL_1_0_1u", name: "1.0.1u" }
20 | name: OpenSSL ${{ matrix.openssl.name }}
21 | steps:
22 | - uses: actions/checkout@v4
23 | - uses: lukka/get-cmake@latest
24 | - uses: ./.github/actions/install/gtest
25 | - uses: ./.github/actions/install/openssl
26 | with:
27 | version: ${{ matrix.openssl.tag }}
28 |
29 | - name: configure
30 | run: cmake --preset unit-tests -DOPENSSL_ROOT_DIR=/tmp
31 | - run: cmake --build --preset unit-tests
32 | - name: test
33 | run: ctest --preset unit-tests --output-on-failure
34 |
35 | - if: github.event_name == 'push' && always()
36 | uses: ./.github/actions/badge
37 | with:
38 | category: openssl
39 | label: ${{ matrix.openssl.name }}
40 |
41 | openssl-no-deprecated:
42 | runs-on: ubuntu-latest
43 | name: OpenSSL 3.0 No Deprecated
44 | steps:
45 | - uses: actions/checkout@v4
46 | - uses: lukka/get-cmake@latest
47 | - uses: ./.github/actions/install/gtest
48 | - uses: ./.github/actions/install/openssl
49 | with:
50 | version: "openssl-3.0.5"
51 |
52 | - name: configure
53 | run: cmake --preset unit-tests -DOPENSSL_ROOT_DIR=/tmp -DCMAKE_CXX_FLAGS="-DOPENSSL_NO_DEPRECATED=1" -DCMAKE_C_FLAGS="-DOPENSSL_NO_DEPRECATED=1"
54 | - run: cmake --build --preset unit-tests
55 | - name: test
56 | run: ctest --preset unit-tests
57 |
58 | libressl:
59 | runs-on: ubuntu-latest
60 | strategy:
61 | fail-fast: false
62 | matrix:
63 | libressl: ["3.5.3", "3.4.3", "3.3.6"]
64 | name: LibreSSL ${{ matrix.libressl }}
65 | steps:
66 | - uses: actions/checkout@v4
67 | - uses: lukka/get-cmake@latest
68 | - uses: ./.github/actions/install/gtest
69 | - uses: ./.github/actions/install/libressl
70 | with:
71 | version: ${{ matrix.libressl }}
72 |
73 | - name: configure
74 | run: cmake --preset unit-tests -DJWT_SSL_LIBRARY:STRING=LibreSSL
75 | - run: cmake --build --preset unit-tests
76 | - name: test
77 | run: ctest --preset unit-tests
78 |
79 | - if: github.event_name == 'push' && always()
80 | uses: ./.github/actions/badge
81 | with:
82 | category: libressl
83 | label: ${{ matrix.libressl }}
84 |
85 | wolfssl:
86 | runs-on: ubuntu-latest
87 | strategy:
88 | matrix:
89 | wolfssl:
90 | - { ref: "v5.1.1-stable", name: "5.1.1"}
91 | - { ref: "v5.2.0-stable", name: "5.2.0" }
92 | - { ref: "v5.3.0-stable", name: "5.3.0"}
93 | - { ref: "v5.7.0-stable", name: "5.7.0"}
94 | name: wolfSSL ${{ matrix.wolfssl.name }}
95 | steps:
96 | - uses: actions/checkout@v4
97 | - uses: lukka/get-cmake@latest
98 | - uses: ./.github/actions/install/gtest
99 | - uses: ./.github/actions/install/wolfssl
100 | with:
101 | version: ${{ matrix.wolfssl.ref }}
102 |
103 | - name: configure
104 | run: cmake --preset unit-tests -DJWT_SSL_LIBRARY:STRING=wolfSSL
105 | - run: cmake --build --preset unit-tests
106 | - name: test
107 | run: ctest --preset unit-tests
108 |
109 | - if: github.event_name == 'push' && always()
110 | uses: ./.github/actions/badge
111 | with:
112 | category: wolfssl
113 | label: ${{ matrix.wolfssl.name }}
114 |
--------------------------------------------------------------------------------
/.github/workflows/targets.yml:
--------------------------------------------------------------------------------
1 | name: Specific Targets CI
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | pull_request:
7 | branches: [master]
8 | paths:
9 | - "CMakeLists.txt"
10 | - "cmake/**"
11 | - "include/jwt-cpp/**"
12 | - "tests/cmake/**"
13 | - ".github/actions/**"
14 | - ".github/workflows/targets.yml"
15 |
16 | jobs:
17 | gcc-4-8:
18 | if: false # There's no existing image with node20 and gcc4.8 https://github.com/actions/checkout/issues/1809
19 | name: GCC 4.8
20 | runs-on: ubuntu-latest
21 | container:
22 | image: ubuntu:bionic-20230530 # 18.04
23 | env:
24 | CC: /usr/bin/gcc-4.8
25 | CXX: /usr/bin/g++-4.8
26 | steps:
27 | - run: |
28 | apt-get update
29 | apt-get install -y g++-4.8 wget make libssl-dev
30 | - uses: actions/checkout@v3 # Can not be upgrade as v4 needs NodeJS 20 doesn't exist next to gcc-4.8
31 | - uses: ./.github/actions/install/cmake
32 | with:
33 | version: "3.26.3"
34 | url: "https://cmake.org/files/v3.26/cmake-3.26.3.tar.gz"
35 |
36 | - name: setup
37 | run: |
38 | mkdir build
39 | cd build
40 | cmake ..
41 | cmake --build .
42 | cmake --install .
43 | - name: test
44 | working-directory: tests/cmake
45 | run: |
46 | CC=gcc-4.8 CXX=g++-4.8 cmake . -DTEST:STRING="defaults-enabled"
47 | cmake --build .
48 |
49 | gcc-12:
50 | name: GCC 12
51 | runs-on: ubuntu-latest
52 | container:
53 | image: ubuntu:jammy-20231004 # 22.04
54 | env:
55 | CC: /usr/bin/gcc-12
56 | CXX: /usr/bin/g++-12
57 | steps:
58 | - run: |
59 | apt-get update
60 | apt-get install -y g++-12 wget make libssl-dev
61 | - uses: actions/checkout@v4
62 | - uses: ./.github/actions/install/cmake
63 | with:
64 | version: "3.26.3"
65 | url: "https://cmake.org/files/v3.26/cmake-3.26.3.tar.gz"
66 |
67 | - name: setup
68 | run: |
69 | mkdir build
70 | cd build
71 | cmake ..
72 | cmake --build .
73 | cmake --install .
74 |
75 | - name: test
76 | working-directory: tests/cmake
77 | run: |
78 | CC=gcc-12 CXX=g++-12 cmake . -DCMAKE_CXX_STANDARD=20 -DTEST:STRING="defaults-enabled"
79 | cmake --build .
80 |
--------------------------------------------------------------------------------
/.github/workflows/traits.yml:
--------------------------------------------------------------------------------
1 | name: Traits CI
2 |
3 | on:
4 | push:
5 | branches: [master]
6 | pull_request:
7 | branches: [master]
8 |
9 | jobs:
10 | traits:
11 | name: Traits (${{ matrix.target.name }})
12 | runs-on: ubuntu-latest
13 | strategy:
14 | matrix:
15 | target:
16 | - { name: "danielaparker-jsoncons", tag: "1.3.2", version: "v1.3.2" }
17 | - { name: "boost-json", tag: "1.78.0", version: "v1.80.0" }
18 | - { name: "nlohmann-json", tag: "3.12.0", version: "v3.12.0" }
19 | - { name: "kazuho-picojson", tag: "111c9be5188f7350c2eac9ddaedd8cca3d7bf394", version: "111c9be" }
20 | - { name: "open-source-parsers-jsoncpp", tag: "1.9.6", version: "v1.9.6" }
21 | steps:
22 | - uses: actions/checkout@v4
23 | - uses: lukka/get-cmake@latest
24 | - name: setup
25 | run: |
26 | mkdir build
27 | cd build
28 | cmake .. -DJWT_BUILD_EXAMPLES=OFF
29 | sudo cmake --install .
30 |
31 | # Install the JSON library
32 | - if: matrix.target.name == 'danielaparker-jsoncons'
33 | uses: ./.github/actions/install/danielaparker-jsoncons
34 | with:
35 | version: ${{matrix.target.tag}}
36 |
37 | - if: matrix.target.name == 'boost-json'
38 | uses: ./.github/actions/install/boost-json
39 | with:
40 | version: ${{matrix.target.tag}}
41 |
42 | - if: matrix.target.name == 'nlohmann-json'
43 | uses: ./.github/actions/install/nlohmann-json
44 | with:
45 | version: ${{matrix.target.tag}}
46 |
47 | - if: matrix.target.name == 'kazuho-picojson'
48 | run: rm -rf include/picojson
49 | - if: matrix.target.name == 'kazuho-picojson'
50 | uses: ./.github/actions/install/kazuho-picojson
51 | with:
52 | version: ${{matrix.target.tag}}
53 |
54 | - if: matrix.target.name == 'open-source-parsers-jsoncpp'
55 | uses: ./.github/actions/install/open-source-parsers-jsoncpp
56 | with:
57 | version: ${{matrix.target.tag}}
58 |
59 | - name: test
60 | working-directory: example/traits
61 | run: |
62 | cmake . -DCMAKE_FIND_DEBUG_MODE=1
63 | cmake --build . --target ${{ matrix.target.name }}
64 | ./${{ matrix.target.name }}
65 |
66 | - name: badge success
67 | if: github.event_name == 'push' && success()
68 | uses: ./.github/actions/badge/write
69 | with:
70 | category: traits
71 | label: ${{ matrix.target.name }}
72 | message: ${{ matrix.target.version }}
73 | color: lightblue # turquoise
74 | - name: badge failure
75 | if: github.event_name == 'push' && !success()
76 | uses: ./.github/actions/badge/write
77 | with:
78 | category: traits
79 | label: ${{ matrix.target.name }}
80 | message: ${{ matrix.target.version }}
81 | color: orange
82 | - if: github.event_name == 'push' && always()
83 | uses: ./.github/actions/badge/publish
84 | with:
85 | github_token: ${{ secrets.GITHUB_TOKEN }}
86 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 | *.VC.db
84 | *.VC.VC.opendb
85 |
86 | # Visual Studio profiler
87 | *.psess
88 | *.vsp
89 | *.vspx
90 | *.sap
91 |
92 | # TFS 2012 Local Workspace
93 | $tf/
94 |
95 | # Guidance Automation Toolkit
96 | *.gpState
97 |
98 | # ReSharper is a .NET coding add-in
99 | _ReSharper*/
100 | *.[Rr]e[Ss]harper
101 | *.DotSettings.user
102 |
103 | # JustCode is a .NET coding add-in
104 | .JustCode
105 |
106 | # TeamCity is a build add-in
107 | _TeamCity*
108 |
109 | # DotCover is a Code Coverage Tool
110 | *.dotCover
111 |
112 | # NCrunch
113 | _NCrunch_*
114 | .*crunch*.local.xml
115 | nCrunchTemp_*
116 |
117 | # MightyMoose
118 | *.mm.*
119 | AutoTest.Net/
120 |
121 | # Web workbench (sass)
122 | .sass-cache/
123 |
124 | # Installshield output folder
125 | [Ee]xpress/
126 |
127 | # DocProject is a documentation generator add-in
128 | DocProject/buildhelp/
129 | DocProject/Help/*.HxT
130 | DocProject/Help/*.HxC
131 | DocProject/Help/*.hhc
132 | DocProject/Help/*.hhk
133 | DocProject/Help/*.hhp
134 | DocProject/Help/Html2
135 | DocProject/Help/html
136 |
137 | # Click-Once directory
138 | publish/
139 |
140 | # Publish Web Output
141 | *.[Pp]ublish.xml
142 | *.azurePubxml
143 | # TODO: Comment the next line if you want to checkin your web deploy settings
144 | # but database connection strings (with potential passwords) will be unencrypted
145 | *.pubxml
146 | *.publishproj
147 |
148 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
149 | # checkin your Azure Web App publish settings, but sensitive information contained
150 | # in these scripts will be unencrypted
151 | PublishScripts/
152 |
153 | # NuGet Packages
154 | *.nupkg
155 | # The packages folder can be ignored because of Package Restore
156 | **/packages/*
157 | # except build/, which is used as an MSBuild target.
158 | !**/packages/build/
159 | # Uncomment if necessary however generally it will be regenerated when needed
160 | #!**/packages/repositories.config
161 | # NuGet v3's project.json files produces more ignoreable files
162 | *.nuget.props
163 | *.nuget.targets
164 |
165 | # Microsoft Azure Build Output
166 | csx/
167 | *.build.csdef
168 |
169 | # Microsoft Azure Emulator
170 | ecf/
171 | rcf/
172 |
173 | # Windows Store app package directories and files
174 | AppPackages/
175 | BundleArtifacts/
176 | Package.StoreAssociation.xml
177 | _pkginfo.txt
178 |
179 | # Visual Studio cache files
180 | # files ending in .cache can be ignored
181 | *.[Cc]ache
182 | # but keep track of directories ending in .cache
183 | !*.[Cc]ache/
184 |
185 | # Others
186 | ClientBin/
187 | ~$*
188 | *~
189 | *.dbmdl
190 | *.dbproj.schemaview
191 | *.pfx
192 | *.publishsettings
193 | node_modules/
194 | orleans.codegen.cs
195 |
196 | # Since there are multiple workflows, uncomment next line to ignore bower_components
197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
198 | #bower_components/
199 |
200 | # RIA/Silverlight projects
201 | Generated_Code/
202 |
203 | # Backup & report files from converting an old project file
204 | # to a newer Visual Studio version. Backup files are not needed,
205 | # because we have git ;-)
206 | _UpgradeReport_Files/
207 | Backup*/
208 | UpgradeLog*.XML
209 | UpgradeLog*.htm
210 |
211 | # SQL Server files
212 | *.mdf
213 | *.ldf
214 |
215 | # Business Intelligence projects
216 | *.rdl.data
217 | *.bim.layout
218 | *.bim_*.settings
219 |
220 | # Microsoft Fakes
221 | FakesAssemblies/
222 |
223 | # GhostDoc plugin setting file
224 | *.GhostDoc.xml
225 |
226 | # Node.js Tools for Visual Studio
227 | .ntvs_analysis.dat
228 |
229 | # Visual Studio 6 build log
230 | *.plg
231 |
232 | # Visual Studio 6 workspace options file
233 | *.opt
234 |
235 | # Visual Studio LightSwitch build output
236 | **/*.HTMLClient/GeneratedArtifacts
237 | **/*.DesktopClient/GeneratedArtifacts
238 | **/*.DesktopClient/ModelManifest.xml
239 | **/*.Server/GeneratedArtifacts
240 | **/*.Server/ModelManifest.xml
241 | _Pvt_Extensions
242 |
243 | # Paket dependency manager
244 | .paket/paket.exe
245 | paket-files/
246 |
247 | # FAKE - F# Make
248 | .fake/
249 |
250 | # JetBrains Rider
251 | .idea/
252 | *.sln.iml
253 |
254 | # =========================
255 | # Operating System Files
256 | # =========================
257 |
258 | # OSX
259 | # =========================
260 |
261 | .DS_Store
262 | .AppleDouble
263 | .LSOverride
264 |
265 | # Thumbnails
266 | ._*
267 |
268 | # Files that might appear in the root of a volume
269 | .DocumentRevisions-V100
270 | .fseventsd
271 | .Spotlight-V100
272 | .TemporaryItems
273 | .Trashes
274 | .VolumeIcon.icns
275 |
276 | # Directories potentially created on remote AFP share
277 | .AppleDB
278 | .AppleDesktop
279 | Network Trash Folder
280 | Temporary Items
281 | .apdisk
282 |
283 | # Windows
284 | # =========================
285 |
286 | # Windows image file caches
287 | Thumbs.db
288 | ehthumbs.db
289 |
290 | # Folder config file
291 | Desktop.ini
292 |
293 | # Recycle Bin used on file shares
294 | $RECYCLE.BIN/
295 |
296 | # Windows Installer files
297 | *.cab
298 | *.msi
299 | *.msm
300 | *.msp
301 |
302 | # Windows shortcuts
303 | *.lnk
304 |
305 | # Linux files
306 | test
307 | *.o
308 | *.o.d
309 |
310 | # IDE-specific files
311 | .vscode/
312 | .vscode/!extensions.json # Allow to provide recommended extensions
313 |
314 | # ClangD cache files
315 | .cache
316 |
317 | build/*
318 | package-lock.json
319 |
320 | CMakeUserPresets.json
321 |
--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "ms-vscode.cpptools",
4 | "ms-vscode.cpptools-extension-pack",
5 | "ms-vscode.cmake-tools",
6 | "twxs.cmake",
7 | "matepek.vscode-catch2-test-adapter",
8 | "GitHub.vscode-github-actions"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.14)
2 | cmake_policy(VERSION 3.14)
3 | if(POLICY CMP0135) # DOWNLOAD_EXTRACT_TIMESTAMP
4 | cmake_policy(SET CMP0135 NEW)
5 | endif()
6 |
7 | # HUNTER_ENABLED is always set if this package is included in a project using hunter (HunterGate sets it) In this case
8 | # we will use hunter as well to stay consistent. If not the use can supply it on configure to force using hunter.
9 | if(HUNTER_ENABLED)
10 | include("cmake/HunterGate.cmake")
11 | huntergate(URL "https://github.com/cpp-pm/hunter/archive/v0.23.314.tar.gz" SHA1
12 | "95c47c92f68edb091b5d6d18924baabe02a6962a")
13 | message(STATUS "jwt-cpp: using hunter for dependency resolution")
14 | endif()
15 |
16 | project(jwt-cpp LANGUAGES CXX)
17 |
18 | option(JWT_BUILD_EXAMPLES "Configure CMake to build examples (or not)" ON)
19 | option(JWT_BUILD_TESTS "Configure CMake to build tests (or not)" OFF)
20 | option(JWT_BUILD_DOCS "Adds a target for building the doxygen documentation" OFF)
21 | option(JWT_ENABLE_COVERAGE "Enable code coverage testing" OFF)
22 | option(JWT_ENABLE_FUZZING "Enable fuzz testing" OFF)
23 |
24 | option(JWT_DISABLE_PICOJSON "Do not provide the picojson template specialiaze" OFF)
25 | option(JWT_DISABLE_BASE64 "Do not include the base64 implementation from this library" OFF)
26 | include(CMakeDependentOption)
27 | cmake_dependent_option(JWT_EXTERNAL_PICOJSON
28 | "Use find_package() to locate picojson, provided to integrate with package managers" OFF
29 | "NOT JWT_DISABLE_PICOJSON" OFF)
30 | cmake_dependent_option(JWT_EXTERNAL_NLOHMANN_JSON
31 | "Use find_package() to locate nlohman-json required for tests and examples" OFF
32 | "JWT_BUILD_EXAMPLES OR JWT_BUILD_TESTS" OFF)
33 |
34 | set(JWT_SSL_LIBRARY_OPTIONS OpenSSL LibreSSL wolfSSL)
35 | set(JWT_SSL_LIBRARY OpenSSL CACHE STRING "Determines which SSL library to build with")
36 | set_property(CACHE JWT_SSL_LIBRARY PROPERTY STRINGS ${JWT_SSL_LIBRARY_OPTIONS})
37 |
38 | set(JWT_JSON_TRAITS_OPTIONS boost-json danielaparker-jsoncons kazuho-picojson nlohmann-json open-source-parsers-jsoncpp)
39 |
40 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
41 |
42 | if(NOT JWT_SSL_LIBRARY IN_LIST JWT_SSL_LIBRARY_OPTIONS)
43 | message(FATAL_ERROR "JWT_SSL_LIBRARY must be one of ${JWT_SSL_LIBRARY_OPTIONS}")
44 | endif()
45 |
46 | # If Hunter is enabled, we configure it to resolve OpenSSL and warn the user if he selected an option not supported by
47 | # hunter. We fall back to the system library in this case.
48 | if(HUNTER_ENABLED)
49 | if(${JWT_SSL_LIBRARY} MATCHES "OpenSSL")
50 | hunter_add_package(OpenSSL)
51 | elseif(${JWT_SSL_LIBRARY} MATCHES "LibreSSL")
52 | message(WARNING "Hunter does not support LibreSSL yet, the system library will be used (if available)")
53 | elseif(${JWT_SSL_LIBRARY} MATCHES "wolfSSL")
54 | message(WARNING "Hunter does not support wolfSSL yet, the system library will be used (if available)")
55 | endif()
56 | if(JWT_EXTERNAL_PICOJSON)
57 | message(WARNING "Hunter does not support picojson yet, the system library will be used (if available)")
58 | endif()
59 | endif()
60 |
61 | # Lookup dependencies
62 | if(${JWT_SSL_LIBRARY} MATCHES "OpenSSL")
63 | find_package(OpenSSL 1.0.1 REQUIRED)
64 | elseif(${JWT_SSL_LIBRARY} MATCHES "LibreSSL")
65 | find_package(LibreSSL 3.0.0 REQUIRED)
66 | elseif(${JWT_SSL_LIBRARY} MATCHES "wolfSSL")
67 | find_package(PkgConfig REQUIRED)
68 | pkg_check_modules(wolfssl REQUIRED IMPORTED_TARGET wolfssl)
69 | list(TRANSFORM wolfssl_INCLUDE_DIRS APPEND "/wolfssl") # This is required to access OpenSSL compatibility API
70 | endif()
71 |
72 | if(NOT JWT_DISABLE_PICOJSON AND JWT_EXTERNAL_PICOJSON)
73 | find_package(picojson 1.3.0 REQUIRED)
74 | endif()
75 |
76 | if(JWT_BUILD_EXAMPLES OR JWT_BUILD_TESTS)
77 | if(JWT_EXTERNAL_NLOHMANN_JSON)
78 | message(STATUS "jwt-cpp: using find_package for nlohmann-json required for tests")
79 | find_package(nlohmann_json CONFIG REQUIRED)
80 | else()
81 | message(STATUS "jwt-cpp: using FetchContent for nlohmann-json required for tests")
82 | include(FetchContent)
83 | fetchcontent_declare(nlohmann_json
84 | URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz
85 | URL_MD5 e155202b2a589137f6804724bd182f12)
86 | fetchcontent_makeavailable(nlohmann_json)
87 | endif()
88 | endif()
89 |
90 | set(JWT_INCLUDE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/include)
91 | set(JWT_HEADER_FILES ${JWT_INCLUDE_PATH}/jwt-cpp/jwt.h)
92 | foreach(traits ${JWT_JSON_TRAITS_OPTIONS})
93 | list(APPEND JWT_HEADER_FILES ${JWT_INCLUDE_PATH}/jwt-cpp/traits/${traits}/defaults.h
94 | ${JWT_INCLUDE_PATH}/jwt-cpp/traits/${traits}/traits.h)
95 | endforeach()
96 |
97 | if(NOT JWT_DISABLE_BASE64)
98 | list(APPEND JWT_HEADER_FILES ${JWT_INCLUDE_PATH}/jwt-cpp/base.h)
99 | endif()
100 |
101 | add_library(jwt-cpp INTERFACE)
102 | add_library(jwt-cpp::jwt-cpp ALIAS jwt-cpp) # To match export
103 | target_compile_features(jwt-cpp INTERFACE cxx_std_11)
104 | if(JWT_DISABLE_BASE64)
105 | target_compile_definitions(jwt-cpp INTERFACE JWT_DISABLE_BASE64)
106 | endif()
107 | if(JWT_DISABLE_PICOJSON)
108 | target_compile_definitions(jwt-cpp INTERFACE JWT_DISABLE_PICOJSON)
109 | endif()
110 |
111 | include(GNUInstallDirs)
112 | include(CMakePackageConfigHelpers)
113 | target_include_directories(jwt-cpp INTERFACE $
114 | $)
115 |
116 | if(${JWT_SSL_LIBRARY} MATCHES "OpenSSL")
117 | target_link_libraries(jwt-cpp INTERFACE OpenSSL::SSL OpenSSL::Crypto)
118 | endif()
119 |
120 | if(${JWT_SSL_LIBRARY} MATCHES "LibreSSL")
121 | target_link_libraries(jwt-cpp INTERFACE LibreSSL::TLS)
122 | endif()
123 |
124 | if(${JWT_SSL_LIBRARY} MATCHES "wolfSSL")
125 | target_link_libraries(jwt-cpp INTERFACE PkgConfig::wolfssl)
126 | # This is required to access OpenSSL compatibility API
127 | target_include_directories(jwt-cpp INTERFACE ${wolfssl_INCLUDE_DIRS})
128 | # This flag is required to have the mandatory header included automatically
129 | # https://github.com/Thalhammer/jwt-cpp/pull/352#discussion_r1627971786
130 | # https://github.com/wolfSSL/wolfssl/blob/3b74a6402998a8b8839e25e31ba8ac74749aa9b0/wolfssl/wolfcrypt/settings.h#L58
131 | target_compile_definitions(jwt-cpp INTERFACE EXTERNAL_OPTS_OPENVPN)
132 | endif()
133 |
134 | if(NOT JWT_DISABLE_PICOJSON AND JWT_EXTERNAL_PICOJSON)
135 | target_link_libraries(jwt-cpp INTERFACE picojson::picojson>)
136 | endif()
137 |
138 | # Hunter needs relative paths so the files are placed correctly
139 | if(NOT JWT_CMAKE_FILES_INSTALL_DIR)
140 | set(JWT_CMAKE_FILES_INSTALL_DIR cmake)
141 | endif()
142 |
143 | configure_package_config_file(
144 | ${CMAKE_CURRENT_LIST_DIR}/cmake/jwt-cpp-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config.cmake
145 | INSTALL_DESTINATION ${JWT_CMAKE_FILES_INSTALL_DIR})
146 | write_basic_package_version_file(${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config-version.cmake VERSION 0.7.1
147 | COMPATIBILITY ExactVersion)
148 |
149 | install(TARGETS jwt-cpp EXPORT jwt-cpp-targets PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
150 | install(EXPORT jwt-cpp-targets NAMESPACE jwt-cpp:: FILE jwt-cpp-targets.cmake
151 | DESTINATION ${JWT_CMAKE_FILES_INSTALL_DIR})
152 | install(DIRECTORY ${JWT_INCLUDE_PATH}/jwt-cpp DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
153 | if(NOT JWT_EXTERNAL_PICOJSON AND NOT JWT_DISABLE_PICOJSON)
154 | install(FILES ${JWT_INCLUDE_PATH}/picojson/picojson.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/picojson)
155 | endif()
156 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-config-version.cmake
157 | DESTINATION ${JWT_CMAKE_FILES_INSTALL_DIR})
158 |
159 | if(JWT_BUILD_EXAMPLES)
160 | add_subdirectory(example)
161 | endif()
162 |
163 | if(JWT_BUILD_TESTS)
164 | enable_testing()
165 | add_subdirectory(tests)
166 | endif()
167 |
168 | if(JWT_ENABLE_FUZZING)
169 | add_subdirectory(tests/fuzz)
170 | endif()
171 |
172 | if(JWT_BUILD_DOCS)
173 | add_subdirectory(docs)
174 | endif()
175 |
--------------------------------------------------------------------------------
/CMakePresets.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 6,
3 | "cmakeMinimumRequired": {
4 | "major": 3,
5 | "minor": 25,
6 | "patch": 0
7 | },
8 | "include": [
9 | "example/CMakePresets.json",
10 | "tests/CMakePresets.json"
11 | ],
12 | "configurePresets": [
13 | {
14 | "name": "dev",
15 | "displayName": "Development",
16 | "inherits": "debug",
17 | "environment": {
18 | "CMAKE_EXPORT_COMPILE_COMMANDS": "ON"
19 | },
20 | "cacheVariables": {
21 | "JWT_BUILD_EXAMPLES": "ON",
22 | "JWT_BUILD_TESTS": "ON"
23 | }
24 | }
25 | ],
26 | "buildPresets": [
27 | {
28 | "name": "dev",
29 | "configurePreset": "dev",
30 | "configuration": "Debug"
31 | }
32 | ]
33 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Dominik Thalhammer
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/cmake/CMakePresets.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 6,
3 | "cmakeMinimumRequired": {
4 | "major": 3,
5 | "minor": 25,
6 | "patch": 0
7 | },
8 | "configurePresets": [
9 | {
10 | "name": "default",
11 | "displayName": "Default Config",
12 | "hidden": true,
13 | "binaryDir": "${sourceDir}/build",
14 | "cacheVariables": {
15 | "JWT_BUILD_EXAMPLES": "OFF",
16 | "JWT_BUILD_TESTS": "OFF"
17 | }
18 | },
19 | {
20 | "name": "debug",
21 | "displayName": "Debug",
22 | "inherits": "default",
23 | "cacheVariables": {
24 | "CMAKE_BUILD_TYPE": "Debug"
25 | }
26 | },
27 | {
28 | "name": "release",
29 | "displayName": "Release",
30 | "inherits": "default",
31 | "cacheVariables": {
32 | "CMAKE_BUILD_TYPE": "Release"
33 | }
34 | }
35 | ],
36 | "buildPresets": [
37 | {
38 | "name": "debug",
39 | "configurePreset": "debug",
40 | "configuration": "Debug"
41 | },
42 | {
43 | "name": "release",
44 | "configurePreset": "release",
45 | "configuration": "Release"
46 | }
47 | ]
48 | }
--------------------------------------------------------------------------------
/cmake/code-coverage.cmake:
--------------------------------------------------------------------------------
1 | set(COVERAGE_CMAKE "${CMAKE_BINARY_DIR}/cmake/CodeCoverage.cmake")
2 | if(NOT EXISTS ${COVERAGE_CMAKE})
3 | set(COVERAGE_URL "https://raw.githubusercontent.com/bilke/cmake-modules/master/CodeCoverage.cmake")
4 | file(DOWNLOAD ${COVERAGE_URL} ${COVERAGE_CMAKE})
5 | endif()
6 |
7 | include(${COVERAGE_CMAKE})
8 |
9 | function(setup_coverage TARGET)
10 | target_compile_options(${TARGET} PRIVATE -g -O0 -fprofile-arcs -ftest-coverage)
11 | target_link_libraries(${TARGET} PRIVATE gcov)
12 | endfunction()
13 |
--------------------------------------------------------------------------------
/cmake/jwt-cpp-config.cmake.in:
--------------------------------------------------------------------------------
1 | @PACKAGE_INIT@
2 |
3 | set(JWT_DISABLE_PICOJSON @JWT_DISABLE_PICOJSON@)
4 | set(JWT_EXTERNAL_PICOJSON @JWT_EXTERNAL_PICOJSON@)
5 | set(JWT_SSL_LIBRARY @JWT_SSL_LIBRARY@)
6 |
7 | include(CMakeFindDependencyMacro)
8 | if(${JWT_SSL_LIBRARY} MATCHES "wolfSSL")
9 | find_dependency(PkgConfig REQUIRED)
10 | pkg_check_modules(wolfssl REQUIRED IMPORTED_TARGET wolfssl)
11 | list(TRANSFORM wolfssl_INCLUDE_DIRS APPEND "/wolfssl") # This is required to access OpenSSL compatibility API
12 | else()
13 | find_dependency(${JWT_SSL_LIBRARY} REQUIRED)
14 | endif()
15 |
16 | if(NOT JWT_DISABLE_PICOJSON AND JWT_EXTERNAL_PICOJSON)
17 | find_dependency(picojson REQUIRED)
18 | endif()
19 |
20 | include("${CMAKE_CURRENT_LIST_DIR}/jwt-cpp-targets.cmake")
21 |
--------------------------------------------------------------------------------
/cmake/private-find-boost-json.cmake:
--------------------------------------------------------------------------------
1 | if(TARGET boost_json)
2 | return()
3 | endif()
4 |
5 | unset(BOOSTJSON_INCLUDE_DIR CACHE)
6 | find_path(BOOSTJSON_INCLUDE_DIR "boost/json.hpp" "boost/json/src.hpp")
7 | if(EXISTS "${BOOSTJSON_INCLUDE_DIR}/boost/json.hpp")
8 | file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/private-boost-json.cpp.in" "#include ")
9 | configure_file("${CMAKE_CURRENT_BINARY_DIR}/private-boost-json.cpp.in" private-boost-json.cpp COPYONLY)
10 | add_library(boost_json "${BOOSTJSON_INCLUDE_DIR}/boost/json.hpp"
11 | "${BOOSTJSON_INCLUDE_DIR}/boost/json/src.hpp"
12 | "${CMAKE_CURRENT_BINARY_DIR}/private-boost-json.cpp")
13 | target_include_directories(boost_json PUBLIC ${BOOSTJSON_INCLUDE_DIR})
14 | target_compile_definitions(boost_json PUBLIC BOOST_JSON_STANDALONE)
15 | target_compile_features(boost_json PUBLIC cxx_std_17)
16 | endif()
17 |
--------------------------------------------------------------------------------
/cmake/private-find-kazuho-picojson.cmake:
--------------------------------------------------------------------------------
1 | if(TARGET kazuho_picojson)
2 | return()
3 | endif()
4 |
5 | unset(PICOJSON_INCLUDE_DIR CACHE)
6 | find_path(PICOJSON_INCLUDE_DIR "picojson/picojson.h")
7 | if(EXISTS "${PICOJSON_INCLUDE_DIR}/picojson/picojson.h")
8 | add_library(kazuho_picojson INTERFACE)
9 | target_include_directories(kazuho_picojson INTERFACE ${PICOJSON_INCLUDE_DIR})
10 | endif()
11 |
--------------------------------------------------------------------------------
/docs/.gitignore:
--------------------------------------------------------------------------------
1 | doxygen-awesome*.css
2 |
--------------------------------------------------------------------------------
/docs/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | file(DOWNLOAD https://raw.githubusercontent.com/jothepro/doxygen-awesome-css/v2.2.1/doxygen-awesome.css
2 | ${CMAKE_CURRENT_LIST_DIR}/doxygen-awesome.css
3 | EXPECTED_HASH SHA256=9b5549928906e9974cc12dcdde9265e016dc2388ec72d5aa3209f4870914a0c8)
4 | file(DOWNLOAD https://raw.githubusercontent.com/jothepro/doxygen-awesome-css/v2.2.1/doxygen-awesome-sidebar-only.css
5 | ${CMAKE_CURRENT_LIST_DIR}/doxygen-awesome-sidebar-only.css
6 | EXPECTED_HASH SHA256=998328b27193b7be007a431bc9be1a6f6855ff4d8fa722ecfdfed79a8931409f)
7 |
8 | execute_process(COMMAND doxygen --version RESULT_VARIABLE DOXYGEN_VERSION_RESULT
9 | OUTPUT_VARIABLE DOXYGEN_VERSION_RAW_OUTPUT)
10 | if(NOT DOXYGEN_VERSION_RESULT EQUAL 0)
11 | message(AUTHOR_WARNING "Unable to get the version of doxygen")
12 | else()
13 | # Extracts the version from the output of the command run before
14 | string(REGEX MATCH "^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)" DOXYGEN_VERSION_OUTPUT
15 | "${DOXYGEN_VERSION_RAW_OUTPUT}")
16 | message(STATUS "doxygen version detected : ${DOXYGEN_VERSION_OUTPUT}")
17 | endif()
18 |
19 | add_custom_target(jwt-docs COMMAND doxygen ${CMAKE_CURRENT_LIST_DIR}/Doxyfile WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
20 | SOURCES ${CMAKE_CURRENT_LIST_DIR}/Doxyfile BYPRODUCTS ${CMAKE_BINARY_DIR}/html/index.html)
21 | add_custom_command(
22 | TARGET jwt-docs POST_BUILD COMMAND ${CMAKE_COMMAND} -E cmake_echo_color --cyan
23 | "You can prview the documentation: ${CMAKE_BINARY_DIR}/html/index.html")
24 |
--------------------------------------------------------------------------------
/docs/faqs.md:
--------------------------------------------------------------------------------
1 | # Frequently Asked Questions
2 |
3 | ## Handling Tokens
4 |
5 | ### The generated JWT token can be decoded, is this correct and secure?
6 |
7 | This is the expected behavior. While the integrity of tokens is ensured by the generated/verified hash,
8 | the contents of the token are only **encoded and not encrypted**. This means you can be sure the token
9 | has not been modified by an unauthorized party, but you should not store confidential information in it.
10 | Anyone with access to the token can read all the claims you put into it. They can however not modify
11 | them unless they have the (private or symmetric) key used to generate the token. If you need to put
12 | confidential information into it, current industry recommends generating a random id and store the data on your
13 | server, using the id to look it up whenever you need.
14 |
15 | ### How can new keys be generated for my application?
16 |
17 | The algorithms provided are all based on OpenSSL, mixing other
18 | cryptographic tools might not work.
19 |
20 | Here are a few links for your convenience:
21 |
22 | - [RSA](https://stackoverflow.com/a/44474607)
23 | - [ED25519](https://stackoverflow.com/a/73118582)
24 | - [ES256](https://github.com/Thalhammer/jwt-cpp/blob/68309438cf30679d6581d6cfbfeea0c028d9ed04/example/es256k.cpp#L5)
25 |
26 | ### Can this library encrypt/decrypt claims?
27 |
28 | No it does not, see [#115](https://github.com/Thalhammer/jwt-cpp/issues/115) for more details.
29 | More importantly you probably don't want to be using JWTs for anything sensitive. Read [this](https://stackoverflow.com/a/43497242/8480874)
30 | for more.
31 |
32 | ### Why are my tokens immediately expired?
33 |
34 | If you are generating tokens that seem to immediately expire, you are likely mixing local time where it is not required. The JWT specification
35 | requires using UTC which this library does.
36 |
37 | Here is a simple example of creating a token that will expire in one hour:
38 |
39 | ```cpp
40 | auto token = jwt::create()
41 | .set_issued_now()
42 | .set_expires_in(std::chrono::seconds{3600})
43 | .sign(jwt::algorithm::hs256{"secret"});
44 | ```
45 |
46 | ### Can you add claims to a signed token?
47 |
48 | The signature includes both the header and payload, according to the RFCs... changing the payload would cause a discrepancy. That should result in the token being rejected. For more details checkout [#194](https://github.com/Thalhammer/jwt-cpp/issues/194).
49 |
50 | ### Why does `jwt::basic_claim` have no `as_object()` method?
51 |
52 | This was brought up in [#212](https://github.com/Thalhammer/jwt-cpp/issues/212#issuecomment-1054344192) and
53 | [#101](https://github.com/Thalhammer/jwt-cpp/issues/101) as it's an excellent question.
54 |
55 | It simply was not required to handle the required keys in JWTs for signing or verification. All the the mandatory keys are numeric, string or array types which required type definitions and access.
56 |
57 | The alternative is to use the `to_json()` method and use the libraries own APIs to pick the data type you need.
58 |
59 | ## Build Issues
60 |
61 | ### Missing \_HMAC and \_EVP_sha256 symbols on Mac
62 |
63 | There seems to exists a problem with the included openssl library of MacOS. Make sure you link to one provided by brew. See [#6](https://github.com/Thalhammer/jwt-cpp/issues/6) for more details.
64 |
65 | ### Building on windows fails with syntax errors
66 |
67 | The header ``, which is often included in Windows projects, defines macros for MIN and MAX which conflicts
68 | with `std::numeric_limits`. See [#5](https://github.com/Thalhammer/jwt-cpp/issues/5) for more details or [this StackOverflow thread](https://stackoverflow.com/questions/13416418/define-nominmax-using-stdmin-max).
69 |
70 | To fix this do one of the following things:
71 |
72 | - define `NOMINMAX`, which suppresses this behavior
73 | - include this library before you `#include `
74 | - place `#undef max` and `#undef min` before you include this library
75 |
--------------------------------------------------------------------------------
/docs/install.md:
--------------------------------------------------------------------------------
1 | # Installation
2 |
3 | There's a number of options to choice from.
4 |
5 | ## Overview
6 |
7 | It's strongly recommended to use a package manager, as JWT-CPP has dependencies for both cryptography and JSON libraries, having a tool to do the heavily lifting can be ideal. Examples of a C and C++ package manager are [Conan](https://conan.io/) and [vcpkg](https://vcpkg.io/). If the version is out of date please check with their respective communities before opening and issue here.
8 |
9 | When manually adding this dependency, and the dependencies this has, check the GitHub Actions and Workflows for some inspiration about how to go about it.
10 |
11 | ### Package Manager
12 |
13 | - Conan:
14 | - vcpkg:
15 | - Nuget:
16 | - Hunter:
17 | - Spack:
18 | - Xrepo:
19 |
20 | Looking for ways to contribute? Help by adding JWT-CPP to your favorite package manager!
21 | [Nixpkgs](https://github.com/NixOS/nixpkgs) for example. Currently many are behind the latest.
22 |
23 | ### Header Only
24 |
25 | Simply downloading the `include/` directory is possible.
26 | Make sure the `jwt-cpp/` subdirectories is visible during compilation.
27 | This **does require** correctly linking to OpenSSL or alternative cryptography library.
28 |
29 | The minimum is `jwt.h` but you will need to add the defines:
30 |
31 | - [`JWT_DISABLE_BASE64`](https://github.com/Thalhammer/jwt-cpp/blob/c9a511f436eaa13857336ebeb44dbc5b7860fe01/include/jwt-cpp/jwt.h#L11)
32 | - [`JWT_DISABLE_PICOJSON`](https://github.com/Thalhammer/jwt-cpp/blob/c9a511f436eaa13857336ebeb44dbc5b7860fe01/include/jwt-cpp/jwt.h#L4)
33 |
34 | In addition to providing your own JSON traits implementation, see [traits.md](traits.md) for more information.
35 |
36 | ### CMake
37 |
38 | Using `find_package` is recommended. Step you environment by [installing OpenSSL](https://github.com/openssl/openssl/blob/master/INSTALL.md). Once complete, configure and install the `jwt-cpp` target using CMake.
39 |
40 | A simple installation of JWT-CPP may look like
41 |
42 | ```sh
43 | cmake .
44 | cmake --build . # Make sure everything compiles and links together
45 | cmake --install .
46 | ```
47 |
48 | Then from your own project
49 |
50 | ```cmake
51 | find_package(jwt-cpp CONFIG REQUIRED)
52 |
53 | target_link_libraries(my_app PRIVATE jwt-cpp::jwt-cpp)
54 | ```
55 |
56 | #### Unsupported Alternatives
57 |
58 | There's also the possibility of using [`FetchContent`](https://cmake.org/cmake/help/latest/module/FetchContent.html#examples) in pull this this project to your build tree.
59 |
60 | ```cmake
61 | include(FetchContent)
62 | fetchcontent_declare(jwt-cpp
63 | GIT_REPOSITORY https://github.com/Thalhammer/jwt-cpp.git
64 | GIT_TAG 08bcf77a687fb06e34138e9e9fa12a4ecbe12332 # v0.7.0 release
65 | )
66 | set(JWT_BUILD_EXAMPLES OFF CACHE BOOL "disable building examples" FORCE)
67 | fetchcontent_makeavailable(jwt-cpp)
68 |
69 | target_link_libraries(my_app PRIVATE jwt-cpp::jwt-cpp)
70 | ```
71 |
72 | Lastly, you can use `add_subdirectory`, this is untested but should work.
73 |
--------------------------------------------------------------------------------
/docs/overrides.css:
--------------------------------------------------------------------------------
1 | html {
2 | --top-nav-height: 150px
3 | }
4 |
5 | @media screen and (min-width: 768px) {
6 | #top {
7 | height: var(--top-nav-height);
8 | }
9 |
10 | #nav-tree, #side-nav {
11 | height: calc(100vh - var(--top-nav-height)) !important;
12 | }
13 |
14 | #side-nav {
15 | top: var(--top-nav-height);
16 | }
17 | }
18 |
19 | .paramname em {
20 | font-weight: 600;
21 | color: var(--primary-dark-color);
22 | }
23 |
24 | a code {
25 | color: var(--primary-color) !important;
26 | }
27 |
--------------------------------------------------------------------------------
/docs/signing.md:
--------------------------------------------------------------------------------
1 | # Signing Tokens
2 |
3 | ## Custom Signature Algorithms
4 |
5 | The libraries design is open so you can implement your own algorithms, see [existing implementations](https://github.com/Thalhammer/jwt-cpp/blob/73f23419235661e89a304ba5ab09d6714fb8dd94/include/jwt-cpp/jwt.h#L874) for ideas.
6 |
7 | ```cpp
8 | struct your_algorithm{
9 | std::string sign(const std::string& /*unused*/, std::error_code& ec) const {
10 | ec.clear();
11 | // CALL YOUR METHOD HERE
12 | return {};
13 | }
14 | void verify(const std::string& /*unused*/, const std::string& signature, std::error_code& ec) const {
15 | ec.clear();
16 | if (!signature.empty()) { ec = error::signature_verification_error::invalid_signature; }
17 |
18 | // CALL YOUR METHOD HERE
19 | }
20 | std::string name() const { return "your_algorithm"; }
21 | };
22 | ```
23 |
24 | Then everything else is the same, just pass in your implementation such as:
25 |
26 | ```cpp
27 | auto token = jwt::create()
28 | .set_id("custom-algo-example")
29 | .set_issued_now()
30 | .set_expires_in(std::chrono::seconds{36000})
31 | .set_payload_claim("sample", jwt::claim(std::string{"test"}))
32 | .sign(your_algorithm{/* what ever you want */});
33 | ```
34 |
--------------------------------------------------------------------------------
/docs/ssl.md:
--------------------------------------------------------------------------------
1 | # Cryptography Libraries
2 |
3 | The underlying cryptography libraries describe [here](../README.md#ssl-compatibility) can be selected when configuring CMake by explicitly setting `JWT_SSL_LIBRARY` to one of three values. The default is to use OpenSSL.
4 |
5 | - OpenSSL
6 | - LibreSSL
7 | - wolfSSL
8 |
9 | Here's an example:
10 |
11 | ```sh
12 | cmake . -DJWT_SSL_LIBRARY:STRING=wolfSSL
13 | ```
14 |
15 | ## Supported Versions
16 |
17 | These are the version which are currently being tested:
18 |
19 | | OpenSSL | LibreSSL | wolfSSL |
20 | | ----------------- | -------------- | -------------- |
21 | | ![1.0.2u][o1.0.2] | ![3.3.6][l3.3] | ![5.1.1][w5.1] |
22 | | ![1.1.0i][o1.1.0] | ![3.4.3][l3.4] | ![5.2.0][w5.2] |
23 | | ![1.1.1q][o1.1.1] | ![3.5.3][l3.5] | ![5.3.0][w5.3] |
24 | | ![3.0.5][o3.0] | | |
25 |
26 | > [!NOTE]
27 | > A complete list of versions tested in the past can be found [here](https://github.com/Thalhammer/jwt-cpp/tree/badges).
28 |
29 | [o1.0.2]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Thalhammer/jwt-cpp/badges/openssl/1.0.2u/shields.json
30 | [o1.1.0]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Thalhammer/jwt-cpp/badges/openssl/1.1.0i/shields.json
31 | [o1.1.1]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Thalhammer/jwt-cpp/badges/openssl/1.1.1q/shields.json
32 | [o3.0]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Thalhammer/jwt-cpp/badges/openssl/3.0.5/shields.json
33 | [l3.3]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Thalhammer/jwt-cpp/badges/libressl/3.3.6/shields.json
34 | [l3.4]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Thalhammer/jwt-cpp/badges/libressl/3.4.3/shields.json
35 | [l3.5]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Thalhammer/jwt-cpp/badges/libressl/3.5.3/shields.json
36 | [w5.1]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Thalhammer/jwt-cpp/badges/wolfssl/5.1.1/shields.json
37 | [w5.2]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Thalhammer/jwt-cpp/badges/wolfssl/5.2.0/shields.json
38 | [w5.3]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Thalhammer/jwt-cpp/badges/wolfssl/5.3.0/shields.json
39 |
40 | ## Notes
41 |
42 | JWT-CPP relies on the OpenSSL API, as a result both LibreSSL and wolfSSL need to include their respective compatibility layers.
43 | Most system already have OpenSSL so it's important to make sure when compiling your application it only includes one. Otherwise you may have missing symbols when linking.
44 |
--------------------------------------------------------------------------------
/docs/traits.md:
--------------------------------------------------------------------------------
1 | # JSON Traits
2 |
3 | Traits define the compatibility mapping for JWT-CPP required functionality to the JSON implementation of choice.
4 |
5 | ## Selecting a JSON library
6 |
7 | For your convenience there are serval traits implementation which provide some popular JSON libraries. They are:
8 |
9 | [![picojson][picojson]](https://github.com/kazuho/picojson)
10 | [![nlohmann][nlohmann]](https://github.com/nlohmann/json)
11 | [![jsoncons][jsoncons]](https://github.com/danielaparker/jsoncons)
12 | [![boostjson][boostjson]](https://github.com/boostorg/json)
13 | [![jsoncpp][jsoncpp]](https://github.com/open-source-parsers/jsoncpp)
14 |
15 | [picojson]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Thalhammer/jwt-cpp/badges/traits/kazuho-picojson/shields.json
16 | [nlohmann]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Thalhammer/jwt-cpp/badges/traits/nlohmann-json/shields.json
17 | [jsoncons]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Thalhammer/jwt-cpp/badges/traits/danielaparker-jsoncons/shields.json
18 | [boostjson]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Thalhammer/jwt-cpp/badges/traits/boost-json/shields.json
19 | [jsoncpp]: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/Thalhammer/jwt-cpp/badges/traits/open-source-parsers-jsoncpp/shields.json
20 |
21 | In order to maintain compatibility, [picojson](https://github.com/kazuho/picojson) is still used to provide a specialized `jwt::claim` along with all helpers. Defining `JWT_DISABLE_PICOJSON` will remove this optional dependency. It's possible to directly include the traits defaults for the other JSON libraries. See the [traits examples](https://github.com/Thalhammer/jwt-cpp/tree/master/example/traits) for details.
22 |
23 | ```cpp
24 | //include "jwt-cpp/traits/author-library/traits.h"
25 | #include "jwt-cpp/traits/nlohmann-json/traits.h"
26 | // There is also a "defaults.h" if you's like to skip providing the
27 | // template specializations for the JSON traits
28 |
29 | int main() {
30 | // All the provided traits are in jwt::traits namespace
31 | using traits = jwt::traits::nlohmann_json;
32 |
33 | const auto time = jwt::date::clock::now();
34 | const auto token = jwt::create()
35 | .set_type("JWT")
36 | .set_issuer("auth.mydomain.io")
37 | .set_audience("mydomain.io")
38 | .set_issued_at(time)
39 | .set_not_before(time)
40 | .set_expires_at(time + std::chrono::minutes{2} + std::chrono::seconds{15})
41 | .sign(jwt::algorithm::none{});
42 | const auto decoded = jwt::decode(token);
43 |
44 | jwt::verify()
45 | .allow_algorithm(jwt::algorithm::none{})
46 | .with_issuer("auth.mydomain.io")
47 | .with_audience("mydomain.io")
48 | .verify(decoded);
49 | ```
50 |
51 | ## Providing your own JSON Traits
52 |
53 | There are several key items that need to be provided to a `jwt::basic_claim` in order for it to be interoperable with you JSON library of choice.
54 |
55 | * type specifications
56 | * conversion from generic "value type" to a specific type
57 | * serialization and parsing
58 |
59 | If ever you are not sure, the traits are heavily checked against static asserts to make sure you provide everything that's required.
60 |
61 | > [!important]
62 | > Not all JSON libraries are a like, you may need to extend certain types such that it can be used. See this [provided implementation](https://github.com/Thalhammer/jwt-cpp/blob/e6b92cca0b7088027269c481fa244e5c39df88ff/include/jwt-cpp/traits/danielaparker-jsoncons/traits.h#L18).
63 |
64 | ```cpp
65 | struct my_favorite_json_library_traits {
66 | // Type Specifications
67 | using value_type = json; // The generic "value type" implementation, most libraries have one
68 | using object_type = json::object_t; // The "map type" string to value
69 | using array_type = json::array_t; // The "list type" array of values
70 | using string_type = std::string; // The "list of chars", must be a narrow char
71 | using number_type = double; // The "precision type"
72 | using integer_type = int64_t; // The "integral type"
73 | using boolean_type = bool; // The "boolean type"
74 |
75 | // Translation between the implementation notion of type, to the jwt::json::type equivalent
76 | static jwt::json::type get_type(const value_type &val) {
77 | using jwt::json::type;
78 |
79 | if (val.type() == json::value_t::object)
80 | return type::object;
81 | if (val.type() == json::value_t::array)
82 | return type::array;
83 | if (val.type() == json::value_t::string)
84 | return type::string;
85 | if (val.type() == json::value_t::number_float)
86 | return type::number;
87 | if (val.type() == json::value_t::number_integer)
88 | return type::integer;
89 | if (val.type() == json::value_t::boolean)
90 | return type::boolean;
91 |
92 | throw std::logic_error("invalid type");
93 | }
94 |
95 | // Conversion from generic value to specific type
96 | static object_type as_object(const value_type &val);
97 | static array_type as_array(const value_type &val);
98 | static string_type as_string(const value_type &val);
99 | static number_type as_number(const value_type &val);
100 | static integer_type as_integer(const value_type &val);
101 | static boolean_type as_boolean(const value_type &val);
102 |
103 | // serialization and parsing
104 | static bool parse(value_type &val, string_type str);
105 | static string_type serialize(const value_type &val); // with no extra whitespace, padding or indentation
106 | };
107 | ```
108 |
--------------------------------------------------------------------------------
/example/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.8)
2 | project(jwt-cpp-examples)
3 |
4 | if(NOT TARGET jwt-cpp)
5 | find_package(jwt-cpp CONFIG REQUIRED)
6 | endif()
7 |
8 | add_subdirectory(traits)
9 |
10 | if(JWT_DISABLE_PICOJSON)
11 | message(FATAL_ERROR "examples require picojson to be available!")
12 | endif()
13 |
14 | add_executable(print-claims print-claims.cpp)
15 | target_link_libraries(print-claims jwt-cpp::jwt-cpp)
16 | add_custom_target(print-claims-run COMMAND print-claims)
17 |
18 | add_executable(private-claims private-claims.cpp)
19 | target_link_libraries(private-claims jwt-cpp::jwt-cpp)
20 | add_custom_target(private-claims-run COMMAND private-claims)
21 |
22 | add_executable(rsa-create rsa-create.cpp)
23 | target_link_libraries(rsa-create jwt-cpp::jwt-cpp)
24 | add_custom_target(rsa-create-run COMMAND rsa-create)
25 |
26 | add_executable(rsa-verify rsa-verify.cpp)
27 | target_link_libraries(rsa-verify jwt-cpp::jwt-cpp)
28 | add_custom_target(rsa-verify-run COMMAND rsa-verify)
29 |
30 | add_executable(jwks-verify jwks-verify.cpp)
31 | target_link_libraries(jwks-verify jwt-cpp::jwt-cpp)
32 | add_custom_target(jwks-verify-run COMMAND jwks-verify)
33 |
34 | add_executable(es256k es256k.cpp)
35 | target_link_libraries(es256k jwt-cpp::jwt-cpp)
36 |
37 | add_executable(partial-claim-verifier partial-claim-verifier.cpp)
38 | target_link_libraries(partial-claim-verifier jwt-cpp::jwt-cpp nlohmann_json::nlohmann_json)
39 |
--------------------------------------------------------------------------------
/example/CMakePresets.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 6,
3 | "cmakeMinimumRequired": {
4 | "major": 3,
5 | "minor": 25,
6 | "patch": 0
7 | },
8 | "include": [
9 | "../cmake/CMakePresets.json"
10 | ],
11 | "configurePresets": [
12 | {
13 | "name": "examples",
14 | "displayName": "Build Examples",
15 | "inherits": "release",
16 | "cacheVariables": {
17 | "JWT_BUILD_EXAMPLES": "ON"
18 | }
19 | }
20 | ],
21 | "buildPresets": [
22 | {
23 | "name": "examples",
24 | "configurePreset": "examples",
25 | "configuration": "Release",
26 | "targets": [
27 | "rsa-create",
28 | "rsa-verify"
29 | ]
30 | }
31 | ]
32 | }
--------------------------------------------------------------------------------
/example/es256k.cpp:
--------------------------------------------------------------------------------
1 | /// @file es256k.cpp
2 | #include
3 | #include
4 |
5 | int main() {
6 | // openssl ecparam -name secp256k1 -genkey -noout -out ec-secp256k1-priv-key.pem
7 | std::string es256k_priv_key = R"(-----BEGIN EC PRIVATE KEY-----
8 | MHQCAQEEIArnQWnspKtjiVuZuzuZ/l1Uqqq8gb2unLJ/6U/Saf4ioAcGBSuBBAAK
9 | oUQDQgAEfy03KCKUpIPMIJBtIG4xOwGm0Np/yHKaK9EDZi0mZ7VUeeNKq476CU5X
10 | 940yusahgneePQrDMF2nWFEtBCOiXQ==
11 | -----END EC PRIVATE KEY-----)";
12 | // openssl ec -in ec-secp256k1-priv-key.pem -pubout > ec-secp256k1-pub-key.pem
13 | std::string es256k_pub_key = R"(-----BEGIN PUBLIC KEY-----
14 | MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEfy03KCKUpIPMIJBtIG4xOwGm0Np/yHKa
15 | K9EDZi0mZ7VUeeNKq476CU5X940yusahgneePQrDMF2nWFEtBCOiXQ==
16 | -----END PUBLIC KEY-----)";
17 |
18 | auto token = jwt::create()
19 | .set_issuer("auth0")
20 | .set_type("JWT")
21 | .set_id("es256k-create-example")
22 | .set_issued_now()
23 | .set_expires_in(std::chrono::seconds{36000})
24 | .set_payload_claim("sample", jwt::claim(std::string{"test"}))
25 | .sign(jwt::algorithm::es256k(es256k_pub_key, es256k_priv_key, "", ""));
26 |
27 | std::cout << "token:\n" << token << '\n';
28 |
29 | auto verify = jwt::verify()
30 | .allow_algorithm(jwt::algorithm::es256k(es256k_pub_key, es256k_priv_key, "", ""))
31 | .with_issuer("auth0");
32 |
33 | auto decoded = jwt::decode(token);
34 |
35 | verify.verify(decoded);
36 |
37 | for (auto& e : decoded.get_header_json())
38 | std::cout << e.first << " = " << e.second << '\n';
39 | for (auto& e : decoded.get_payload_json())
40 | std::cout << e.first << " = " << e.second << '\n';
41 | }
42 |
--------------------------------------------------------------------------------
/example/partial-claim-verifier.cpp:
--------------------------------------------------------------------------------
1 | /// @file partial-claim-verifier.cpp
2 | #include "jwt-cpp/traits/nlohmann-json/defaults.h"
3 |
4 | #include
5 |
6 | int main() {
7 | std::string const rsa_priv_key = R"(-----BEGIN PRIVATE KEY-----
8 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4ZtdaIrd1BPIJ
9 | tfnF0TjIK5inQAXZ3XlCrUlJdP+XHwIRxdv1FsN12XyMYO/6ymLmo9ryoQeIrsXB
10 | XYqlET3zfAY+diwCb0HEsVvhisthwMU4gZQu6TYW2s9LnXZB5rVtcBK69hcSlA2k
11 | ZudMZWxZcj0L7KMfO2rIvaHw/qaVOE9j0T257Z8Kp2CLF9MUgX0ObhIsdumFRLaL
12 | DvDUmBPr2zuh/34j2XmWwn1yjN/WvGtdfhXW79Ki1S40HcWnygHgLV8sESFKUxxQ
13 | mKvPUTwDOIwLFL5WtE8Mz7N++kgmDcmWMCHc8kcOIu73Ta/3D4imW7VbKgHZo9+K
14 | 3ESFE3RjAgMBAAECggEBAJTEIyjMqUT24G2FKiS1TiHvShBkTlQdoR5xvpZMlYbN
15 | tVWxUmrAGqCQ/TIjYnfpnzCDMLhdwT48Ab6mQJw69MfiXwc1PvwX1e9hRscGul36
16 | ryGPKIVQEBsQG/zc4/L2tZe8ut+qeaK7XuYrPp8bk/X1e9qK5m7j+JpKosNSLgJj
17 | NIbYsBkG2Mlq671irKYj2hVZeaBQmWmZxK4fw0Istz2WfN5nUKUeJhTwpR+JLUg4
18 | ELYYoB7EO0Cej9UBG30hbgu4RyXA+VbptJ+H042K5QJROUbtnLWuuWosZ5ATldwO
19 | u03dIXL0SH0ao5NcWBzxU4F2sBXZRGP2x/jiSLHcqoECgYEA4qD7mXQpu1b8XO8U
20 | 6abpKloJCatSAHzjgdR2eRDRx5PMvloipfwqA77pnbjTUFajqWQgOXsDTCjcdQui
21 | wf5XAaWu+TeAVTytLQbSiTsBhrnoqVrr3RoyDQmdnwHT8aCMouOgcC5thP9vQ8Us
22 | rVdjvRRbnJpg3BeSNimH+u9AHgsCgYEA0EzcbOltCWPHRAY7B3Ge/AKBjBQr86Kv
23 | TdpTlxePBDVIlH+BM6oct2gaSZZoHbqPjbq5v7yf0fKVcXE4bSVgqfDJ/sZQu9Lp
24 | PTeV7wkk0OsAMKk7QukEpPno5q6tOTNnFecpUhVLLlqbfqkB2baYYwLJR3IRzboJ
25 | FQbLY93E8gkCgYB+zlC5VlQbbNqcLXJoImqItgQkkuW5PCgYdwcrSov2ve5r/Acz
26 | FNt1aRdSlx4176R3nXyibQA1Vw+ztiUFowiP9WLoM3PtPZwwe4bGHmwGNHPIfwVG
27 | m+exf9XgKKespYbLhc45tuC08DATnXoYK7O1EnUINSFJRS8cezSI5eHcbQKBgQDC
28 | PgqHXZ2aVftqCc1eAaxaIRQhRmY+CgUjumaczRFGwVFveP9I6Gdi+Kca3DE3F9Pq
29 | PKgejo0SwP5vDT+rOGHN14bmGJUMsX9i4MTmZUZ5s8s3lXh3ysfT+GAhTd6nKrIE
30 | kM3Nh6HWFhROptfc6BNusRh1kX/cspDplK5x8EpJ0QKBgQDWFg6S2je0KtbV5PYe
31 | RultUEe2C0jYMDQx+JYxbPmtcopvZQrFEur3WKVuLy5UAy7EBvwMnZwIG7OOohJb
32 | vkSpADK6VPn9lbqq7O8cTedEHttm6otmLt8ZyEl3hZMaL3hbuRj6ysjmoFKx6CrX
33 | rK0/Ikt5ybqUzKCMJZg2VKGTxg==
34 | -----END PRIVATE KEY-----)";
35 |
36 | auto role_claim = nlohmann::json{{"my-service", {{"roles", {"foo", "bar", "baz"}}}}};
37 |
38 | auto token = jwt::create()
39 | .set_issuer("auth0")
40 | .set_type("JWT")
41 | .set_id("rsa-create-example")
42 | .set_issued_now()
43 | .set_expires_in(std::chrono::seconds{36000})
44 | .set_payload_claim("resource-access", role_claim)
45 | .sign(jwt::algorithm::rs256("", rsa_priv_key, "", ""));
46 |
47 | std::cout << "token: " << token << '\n';
48 |
49 | std::string const rsa_pub_key = R"(-----BEGIN PUBLIC KEY-----
50 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuGbXWiK3dQTyCbX5xdE4
51 | yCuYp0AF2d15Qq1JSXT/lx8CEcXb9RbDddl8jGDv+spi5qPa8qEHiK7FwV2KpRE9
52 | 83wGPnYsAm9BxLFb4YrLYcDFOIGULuk2FtrPS512Qea1bXASuvYXEpQNpGbnTGVs
53 | WXI9C+yjHztqyL2h8P6mlThPY9E9ue2fCqdgixfTFIF9Dm4SLHbphUS2iw7w1JgT
54 | 69s7of9+I9l5lsJ9cozf1rxrXX4V1u/SotUuNB3Fp8oB4C1fLBEhSlMcUJirz1E8
55 | AziMCxS+VrRPDM+zfvpIJg3JljAh3PJHDiLu902v9w+Iplu1WyoB2aPfitxEhRN0
56 | YwIDAQAB
57 | -----END PUBLIC KEY-----)";
58 |
59 | auto decoded = jwt::decode(token);
60 |
61 | for (const auto& e : decoded.get_payload_json())
62 | std::cout << e.first << " = " << e.second << '\n';
63 |
64 | std::cout << '\n';
65 |
66 | auto role_verifier = [](const jwt::verify_context& ctx, std::error_code& ec) {
67 | using error = jwt::error::token_verification_error;
68 |
69 | auto c = ctx.get_claim(false, ec);
70 | if (ec) return;
71 | if (c.get_type() == jwt::json::type::object) {
72 | auto obj = c.to_json();
73 | try {
74 | auto roles = obj["my-service"]["roles"].get();
75 | if (roles.end() == std::find(roles.begin(), roles.end(), "foo")) ec = error::claim_value_missmatch;
76 | } catch (const std::exception& ex) { ec = error::claim_value_missmatch; }
77 | } else
78 | ec = error::claim_type_missmatch;
79 | };
80 |
81 | /* [verifier check custom claim] */
82 | auto verifier = jwt::verify()
83 | .allow_algorithm(jwt::algorithm::rs256(rsa_pub_key, "", "", ""))
84 | .with_issuer("auth0")
85 | // Check for "foo" in /my-service/role
86 | .with_claim("resource-access", role_verifier);
87 | /* [verifier check custom claim] */
88 |
89 | try {
90 | verifier.verify(decoded);
91 | std::cout << "Success!" << '\n';
92 | } catch (const std::exception& ex) { std::cout << "Error: " << ex.what() << '\n'; }
93 |
94 | return 0;
95 | }
96 |
--------------------------------------------------------------------------------
/example/print-claims.cpp:
--------------------------------------------------------------------------------
1 | /// @file print-claims.cpp
2 | #include
3 | #include
4 |
5 | int main() {
6 | const std::string token =
7 | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCIsInNhbXBsZSI6InRlc3QifQ.lQm3N2bVlqt2-"
8 | "1L-FsOjtR6uE-L4E9zJutMWKIe1v1M";
9 | auto decoded = jwt::decode(token);
10 |
11 | for (auto& e : decoded.get_payload_json())
12 | std::cout << e.first << " = " << e.second << '\n';
13 | }
14 |
--------------------------------------------------------------------------------
/example/private-claims.cpp:
--------------------------------------------------------------------------------
1 | /// @file private-claims.cpp
2 | #include
3 |
4 | #include
5 | #include
6 |
7 | using sec = std::chrono::seconds;
8 | using min = std::chrono::minutes;
9 |
10 | int main() {
11 | jwt::claim from_raw_json;
12 | std::istringstream iss{R"##({"api":{"array":[1,2,3],"null":null}})##"};
13 | iss >> from_raw_json;
14 |
15 | jwt::claim::set_t list{"once", "twice"};
16 | std::vector big_numbers{727663072ULL, 770979831ULL, 427239169ULL, 525936436ULL};
17 |
18 | const auto time = jwt::date::clock::now();
19 | const auto token = jwt::create()
20 | .set_type("JWT")
21 | .set_issuer("auth.mydomain.io")
22 | .set_audience("mydomain.io")
23 | .set_issued_at(time)
24 | .set_not_before(time - sec{15})
25 | .set_expires_at(time + sec{15} + min{2})
26 | .set_payload_claim("boolean", picojson::value(true))
27 | .set_payload_claim("integer", picojson::value(int64_t{12345}))
28 | .set_payload_claim("precision", picojson::value(12.345))
29 | .set_payload_claim("strings", jwt::claim(list))
30 | .set_payload_claim("array", jwt::claim(big_numbers.begin(), big_numbers.end()))
31 | .set_payload_claim("object", from_raw_json)
32 | .sign(jwt::algorithm::none{});
33 |
34 | const auto decoded = jwt::decode(token);
35 |
36 | const auto api_array = decoded.get_payload_claim("object").to_json().get("api").get("array");
37 | std::cout << "api array = " << api_array << '\n';
38 |
39 | /* [verify exact claim] */
40 | jwt::verify()
41 | .allow_algorithm(jwt::algorithm::none{})
42 | .with_issuer("auth.mydomain.io")
43 | .with_audience("mydomain.io")
44 | .with_claim("object", from_raw_json) // Match the exact JSON content
45 | .verify(decoded);
46 | /* [verify exact claim] */
47 |
48 | return 0;
49 | }
50 |
--------------------------------------------------------------------------------
/example/rsa-create.cpp:
--------------------------------------------------------------------------------
1 | /// @file rsa-create.cpp
2 | #include
3 | #include
4 |
5 | int main() {
6 | std::string const rsa_priv_key = R"(-----BEGIN PRIVATE KEY-----
7 | MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC4ZtdaIrd1BPIJ
8 | tfnF0TjIK5inQAXZ3XlCrUlJdP+XHwIRxdv1FsN12XyMYO/6ymLmo9ryoQeIrsXB
9 | XYqlET3zfAY+diwCb0HEsVvhisthwMU4gZQu6TYW2s9LnXZB5rVtcBK69hcSlA2k
10 | ZudMZWxZcj0L7KMfO2rIvaHw/qaVOE9j0T257Z8Kp2CLF9MUgX0ObhIsdumFRLaL
11 | DvDUmBPr2zuh/34j2XmWwn1yjN/WvGtdfhXW79Ki1S40HcWnygHgLV8sESFKUxxQ
12 | mKvPUTwDOIwLFL5WtE8Mz7N++kgmDcmWMCHc8kcOIu73Ta/3D4imW7VbKgHZo9+K
13 | 3ESFE3RjAgMBAAECggEBAJTEIyjMqUT24G2FKiS1TiHvShBkTlQdoR5xvpZMlYbN
14 | tVWxUmrAGqCQ/TIjYnfpnzCDMLhdwT48Ab6mQJw69MfiXwc1PvwX1e9hRscGul36
15 | ryGPKIVQEBsQG/zc4/L2tZe8ut+qeaK7XuYrPp8bk/X1e9qK5m7j+JpKosNSLgJj
16 | NIbYsBkG2Mlq671irKYj2hVZeaBQmWmZxK4fw0Istz2WfN5nUKUeJhTwpR+JLUg4
17 | ELYYoB7EO0Cej9UBG30hbgu4RyXA+VbptJ+H042K5QJROUbtnLWuuWosZ5ATldwO
18 | u03dIXL0SH0ao5NcWBzxU4F2sBXZRGP2x/jiSLHcqoECgYEA4qD7mXQpu1b8XO8U
19 | 6abpKloJCatSAHzjgdR2eRDRx5PMvloipfwqA77pnbjTUFajqWQgOXsDTCjcdQui
20 | wf5XAaWu+TeAVTytLQbSiTsBhrnoqVrr3RoyDQmdnwHT8aCMouOgcC5thP9vQ8Us
21 | rVdjvRRbnJpg3BeSNimH+u9AHgsCgYEA0EzcbOltCWPHRAY7B3Ge/AKBjBQr86Kv
22 | TdpTlxePBDVIlH+BM6oct2gaSZZoHbqPjbq5v7yf0fKVcXE4bSVgqfDJ/sZQu9Lp
23 | PTeV7wkk0OsAMKk7QukEpPno5q6tOTNnFecpUhVLLlqbfqkB2baYYwLJR3IRzboJ
24 | FQbLY93E8gkCgYB+zlC5VlQbbNqcLXJoImqItgQkkuW5PCgYdwcrSov2ve5r/Acz
25 | FNt1aRdSlx4176R3nXyibQA1Vw+ztiUFowiP9WLoM3PtPZwwe4bGHmwGNHPIfwVG
26 | m+exf9XgKKespYbLhc45tuC08DATnXoYK7O1EnUINSFJRS8cezSI5eHcbQKBgQDC
27 | PgqHXZ2aVftqCc1eAaxaIRQhRmY+CgUjumaczRFGwVFveP9I6Gdi+Kca3DE3F9Pq
28 | PKgejo0SwP5vDT+rOGHN14bmGJUMsX9i4MTmZUZ5s8s3lXh3ysfT+GAhTd6nKrIE
29 | kM3Nh6HWFhROptfc6BNusRh1kX/cspDplK5x8EpJ0QKBgQDWFg6S2je0KtbV5PYe
30 | RultUEe2C0jYMDQx+JYxbPmtcopvZQrFEur3WKVuLy5UAy7EBvwMnZwIG7OOohJb
31 | vkSpADK6VPn9lbqq7O8cTedEHttm6otmLt8ZyEl3hZMaL3hbuRj6ysjmoFKx6CrX
32 | rK0/Ikt5ybqUzKCMJZg2VKGTxg==
33 | -----END PRIVATE KEY-----)";
34 |
35 | auto token = jwt::create()
36 | .set_issuer("auth0")
37 | .set_type("JWT")
38 | .set_id("rsa-create-example")
39 | .set_issued_now()
40 | .set_expires_in(std::chrono::seconds{36000})
41 | .set_payload_claim("sample", jwt::claim(std::string{"test"}))
42 | .sign(jwt::algorithm::rs256("", rsa_priv_key, "", ""));
43 |
44 | std::cout << "token:\n" << token << '\n';
45 | }
46 |
--------------------------------------------------------------------------------
/example/rsa-verify.cpp:
--------------------------------------------------------------------------------
1 | /// \file rsa-verify.cpp
2 | #include
3 | #include
4 |
5 | int main() {
6 | const std::string rsa_pub_key = R"(-----BEGIN PUBLIC KEY-----
7 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuGbXWiK3dQTyCbX5xdE4
8 | yCuYp0AF2d15Qq1JSXT/lx8CEcXb9RbDddl8jGDv+spi5qPa8qEHiK7FwV2KpRE9
9 | 83wGPnYsAm9BxLFb4YrLYcDFOIGULuk2FtrPS512Qea1bXASuvYXEpQNpGbnTGVs
10 | WXI9C+yjHztqyL2h8P6mlThPY9E9ue2fCqdgixfTFIF9Dm4SLHbphUS2iw7w1JgT
11 | 69s7of9+I9l5lsJ9cozf1rxrXX4V1u/SotUuNB3Fp8oB4C1fLBEhSlMcUJirz1E8
12 | AziMCxS+VrRPDM+zfvpIJg3JljAh3PJHDiLu902v9w+Iplu1WyoB2aPfitxEhRN0
13 | YwIDAQAB
14 | -----END PUBLIC KEY-----)";
15 |
16 | const std::string token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9."
17 | "VA2i1ui1cnoD6I3wnji1WAVCf29EekysvevGrT2GXqK1dDMc8"
18 | "HAZCTQxa1Q8NppnpYV-hlqxh-X3Bb0JOePTGzjynpNZoJh2aHZD-"
19 | "GKpZt7OO1Zp8AFWPZ3p8Cahq8536fD8RiBES9jRsvChZvOqA7gMcFc4"
20 | "YD0iZhNIcI7a654u5yPYyTlf5kjR97prCf_OXWRn-bYY74zna4p_bP9oWCL4BkaoRcMxi-"
21 | "IR7kmVcCnvbYqyIrKloXP2qPO442RBGqU7Ov9"
22 | "sGQxiVqtRHKXZR9RbfvjrErY1KGiCp9M5i2bsUHadZEY44FE2jiOmx-"
23 | "uc2z5c05CCXqVSpfCjWbh9gQ";
24 |
25 | /* [allow rsa algorithm] */
26 | auto verify = jwt::verify()
27 | // We only need an RSA public key to verify tokens
28 | .allow_algorithm(jwt::algorithm::rs256(rsa_pub_key, "", "", ""))
29 | // We expect token to come from a known authorization server
30 | .with_issuer("auth0");
31 | /* [allow rsa algorithm] */
32 |
33 | auto decoded = jwt::decode(token);
34 |
35 | verify.verify(decoded);
36 |
37 | for (auto& e : decoded.get_header_json())
38 | std::cout << e.first << " = " << e.second << '\n';
39 | for (auto& e : decoded.get_payload_json())
40 | std::cout << e.first << " = " << e.second << '\n';
41 | }
42 |
--------------------------------------------------------------------------------
/example/traits/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.8)
2 | project(jwt-cpp-traits)
3 |
4 | if(NOT TARGET jwt-cpp)
5 | find_package(jwt-cpp CONFIG REQUIRED)
6 | endif()
7 |
8 | find_package(jsoncons CONFIG)
9 | if(TARGET jsoncons)
10 | add_executable(danielaparker-jsoncons danielaparker-jsoncons.cpp)
11 | target_link_libraries(danielaparker-jsoncons jwt-cpp::jwt-cpp jsoncons)
12 | endif()
13 |
14 | include("../../cmake/private-find-boost-json.cmake")
15 | if(TARGET boost_json)
16 | add_executable(boost-json boost-json.cpp)
17 | target_link_libraries(boost-json jwt-cpp::jwt-cpp boost_json)
18 | endif()
19 |
20 | find_package(nlohmann_json CONFIG)
21 | if(TARGET nlohmann_json::nlohmann_json)
22 | add_executable(nlohmann-json nlohmann-json.cpp)
23 | target_link_libraries(nlohmann-json nlohmann_json::nlohmann_json jwt-cpp::jwt-cpp)
24 | endif()
25 |
26 | include("../../cmake/private-find-kazuho-picojson.cmake")
27 | if(TARGET kazuho_picojson)
28 | add_executable(kazuho-picojson kazuho-picojson.cpp)
29 | target_link_libraries(kazuho-picojson jwt-cpp::jwt-cpp kazuho_picojson)
30 | endif()
31 |
32 | find_package(jsoncpp CONFIG)
33 | if(TARGET jsoncpp_static)
34 | add_executable(open-source-parsers-jsoncpp open-source-parsers-jsoncpp.cpp)
35 | target_link_libraries(open-source-parsers-jsoncpp jsoncpp_static jwt-cpp::jwt-cpp)
36 | endif()
37 |
--------------------------------------------------------------------------------
/example/traits/README.md:
--------------------------------------------------------------------------------
1 | # Traits Examples
2 |
3 | These example require upstream CMake installation to work. There are exceptions:
4 |
5 | - For Boost.JSON headers must be located by custom CMake.
6 | - For PicoJSON headers must be located by custom CMake.
7 |
--------------------------------------------------------------------------------
/example/traits/boost-json.cpp:
--------------------------------------------------------------------------------
1 | #include "jwt-cpp/traits/boost-json/traits.h"
2 |
3 | // #include // You may require this if you are not building it elsewhere
4 | #include
5 | #include
6 |
7 | int main() {
8 | using sec = std::chrono::seconds;
9 | using min = std::chrono::minutes;
10 | using traits = jwt::traits::boost_json;
11 | using claim = jwt::basic_claim;
12 |
13 | traits::value_type raw_value;
14 | traits::parse(raw_value, R"##({"api":{"array":[1,2,3],"null":null}})##");
15 | claim from_raw_json(raw_value);
16 |
17 | claim::set_t list{"once", "twice"};
18 | std::vector big_numbers{727663072ULL, 770979831ULL, 427239169ULL, 525936436ULL};
19 |
20 | const auto time = jwt::date::clock::now();
21 | const auto token = jwt::create()
22 | .set_type("JWT")
23 | .set_issuer("auth.mydomain.io")
24 | .set_audience("mydomain.io")
25 | .set_issued_at(time)
26 | .set_not_before(time)
27 | .set_expires_at(time + min{2} + sec{15})
28 | .set_payload_claim("boolean", true)
29 | .set_payload_claim("integer", 12345)
30 | .set_payload_claim("precision", 12.3456789)
31 | .set_payload_claim("strings", claim(list))
32 | .set_payload_claim("array", claim{big_numbers.begin(), big_numbers.end()})
33 | .set_payload_claim("object", from_raw_json)
34 | .sign(jwt::algorithm::none{});
35 | const auto decoded = jwt::decode(token);
36 |
37 | for (auto& e : decoded.get_header_json())
38 | std::cout << e.key() << " = " << e.value() << '\n';
39 |
40 | const auto array =
41 | traits::as_array(decoded.get_payload_claim("object").to_json().as_object()["api"].as_object()["array"]);
42 | std::cout << "payload /object/api/array = " << array << '\n';
43 |
44 | jwt::verify()
45 | .allow_algorithm(jwt::algorithm::none{})
46 | .with_issuer("auth.mydomain.io")
47 | .with_audience("mydomain.io")
48 | .with_claim("object", from_raw_json)
49 | .verify(decoded);
50 |
51 | return 0;
52 | }
53 |
--------------------------------------------------------------------------------
/example/traits/danielaparker-jsoncons.cpp:
--------------------------------------------------------------------------------
1 | #include "jwt-cpp/traits/danielaparker-jsoncons/traits.h"
2 |
3 | #include
4 | #include
5 |
6 | int main() {
7 | using sec = std::chrono::seconds;
8 | using min = std::chrono::minutes;
9 | using traits = jwt::traits::danielaparker_jsoncons;
10 | using claim = jwt::basic_claim;
11 |
12 | claim from_raw_json;
13 | std::istringstream iss{R"##({"api":{"array":[1,2,3],"null":null}})##"};
14 | iss >> from_raw_json;
15 |
16 | claim::set_t list{"once", "twice"};
17 | std::vector big_numbers{727663072ULL, 770979831ULL, 427239169ULL, 525936436ULL};
18 |
19 | const auto time = jwt::date::clock::now();
20 | const auto token = jwt::create()
21 | .set_type("JWT")
22 | .set_issuer("auth.mydomain.io")
23 | .set_audience("mydomain.io")
24 | .set_issued_at(time)
25 | .set_not_before(time)
26 | .set_expires_at(time + min{2} + sec{15})
27 | .set_payload_claim("boolean", true)
28 | .set_payload_claim("integer", 12345)
29 | .set_payload_claim("precision", 12.3456789)
30 | .set_payload_claim("strings", list)
31 | .set_payload_claim("array", claim{big_numbers.begin(), big_numbers.end()})
32 | .set_payload_claim("object", from_raw_json)
33 | .sign(jwt::algorithm::none{});
34 | const auto decoded = jwt::decode(token);
35 |
36 | const auto array = traits::as_array(decoded.get_payload_claim("object").to_json()["api"]["array"]);
37 | std::cout << "payload /object/api/array = " << jsoncons::pretty_print(traits::json(array)) << '\n';
38 |
39 | jwt::verify()
40 | .allow_algorithm(jwt::algorithm::none{})
41 | .with_issuer("auth.mydomain.io")
42 | .with_audience("mydomain.io")
43 | .with_claim("object", from_raw_json)
44 | .verify(decoded);
45 |
46 | return 0;
47 | }
48 |
--------------------------------------------------------------------------------
/example/traits/kazuho-picojson.cpp:
--------------------------------------------------------------------------------
1 | #include "jwt-cpp/traits/kazuho-picojson/traits.h"
2 |
3 | #include
4 | #include
5 |
6 | int main() {
7 | using sec = std::chrono::seconds;
8 | using min = std::chrono::minutes;
9 | using traits = jwt::traits::kazuho_picojson;
10 | using claim = jwt::basic_claim;
11 |
12 | claim from_raw_json;
13 | std::istringstream iss{R"##({"api":{"array":[1,2,3],"null":null}})##"};
14 | iss >> from_raw_json;
15 |
16 | claim::set_t list{"once", "twice"};
17 | std::vector big_numbers{727663072ULL, 770979831ULL, 427239169ULL, 525936436ULL};
18 |
19 | const auto time = jwt::date::clock::now();
20 | const auto token = jwt::create()
21 | .set_type("JWT")
22 | .set_issuer("auth.mydomain.io")
23 | .set_audience("mydomain.io")
24 | .set_issued_at(time)
25 | .set_not_before(time)
26 | .set_expires_at(time + min{2} + sec{15})
27 | .set_payload_claim("boolean", picojson::value(true))
28 | .set_payload_claim("integer", picojson::value(int64_t{12345}))
29 | .set_payload_claim("precision", picojson::value(12.345))
30 | .set_payload_claim("strings", claim(list))
31 | .set_payload_claim("array", claim(big_numbers.begin(), big_numbers.end()))
32 | .set_payload_claim("object", from_raw_json)
33 | .sign(jwt::algorithm::none{});
34 | const auto decoded = jwt::decode(token);
35 |
36 | const auto api_array = decoded.get_payload_claim("object").to_json().get("api").get("array");
37 | std::cout << "api array = " << api_array << '\n';
38 |
39 | jwt::verify()
40 | .allow_algorithm(jwt::algorithm::none{})
41 | .with_issuer("auth.mydomain.io")
42 | .with_audience("mydomain.io")
43 | .with_claim("object", from_raw_json)
44 | .verify(decoded);
45 |
46 | return 0;
47 | }
48 |
--------------------------------------------------------------------------------
/example/traits/nlohmann-json.cpp:
--------------------------------------------------------------------------------
1 | #include "jwt-cpp/traits/nlohmann-json/traits.h"
2 |
3 | #include
4 | #include
5 |
6 | int main() {
7 | using sec = std::chrono::seconds;
8 | using min = std::chrono::minutes;
9 | using traits = jwt::traits::nlohmann_json;
10 | using claim = jwt::basic_claim;
11 |
12 | claim from_raw_json;
13 | std::istringstream iss{R"##({"api":{"array":[1,2,3],"null":null}})##"};
14 | iss >> from_raw_json;
15 |
16 | claim::set_t list{"once", "twice"};
17 | std::vector big_numbers{727663072ULL, 770979831ULL, 427239169ULL, 525936436ULL};
18 |
19 | const auto time = jwt::date::clock::now();
20 | const auto token = jwt::create()
21 | .set_type("JWT")
22 | .set_issuer("auth.mydomain.io")
23 | .set_audience("mydomain.io")
24 | .set_issued_at(time)
25 | .set_not_before(time)
26 | .set_expires_at(time + min{2} + sec{15})
27 | .set_payload_claim("boolean", true)
28 | .set_payload_claim("integer", 12345)
29 | .set_payload_claim("precision", 12.3456789)
30 | .set_payload_claim("strings", list)
31 | .set_payload_claim("array", {big_numbers.begin(), big_numbers.end()})
32 | .set_payload_claim("object", from_raw_json)
33 | .sign(jwt::algorithm::none{});
34 | const auto decoded = jwt::decode(token);
35 |
36 | const auto array = traits::as_array(decoded.get_payload_claim("object").to_json()["api"]["array"]);
37 | std::cout << "payload /object/api/array = " << array << '\n';
38 |
39 | jwt::verify()
40 | .allow_algorithm(jwt::algorithm::none{})
41 | .with_issuer("auth.mydomain.io")
42 | .with_audience("mydomain.io")
43 | .with_claim("object", from_raw_json)
44 | .verify(decoded);
45 |
46 | return 0;
47 | }
48 |
--------------------------------------------------------------------------------
/example/traits/open-source-parsers-jsoncpp.cpp:
--------------------------------------------------------------------------------
1 | #include "jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h"
2 |
3 | #include
4 | #include
5 |
6 | int main() {
7 | using sec = std::chrono::seconds;
8 | using min = std::chrono::minutes;
9 | using traits = jwt::traits::open_source_parsers_jsoncpp;
10 | using claim = jwt::basic_claim;
11 |
12 | claim from_raw_json;
13 | std::istringstream iss{R"##({"api":{"array":[1,2,3],"null":null}})##"};
14 | iss >> from_raw_json;
15 |
16 | claim::set_t list{"once", "twice"};
17 | std::vector big_numbers{727663072ULL, 770979831ULL, 427239169ULL, 525936436ULL};
18 |
19 | const auto time = jwt::date::clock::now();
20 | const auto token = jwt::create()
21 | .set_type("JWT")
22 | .set_issuer("auth.mydomain.io")
23 | .set_audience("mydomain.io")
24 | .set_issued_at(time)
25 | .set_not_before(time)
26 | .set_expires_at(time + min{2} + sec{15})
27 | .set_payload_claim("boolean", true)
28 | .set_payload_claim("integer", 12345)
29 | .set_payload_claim("precision", 12.3456789)
30 | .set_payload_claim("strings", claim(list))
31 | .set_payload_claim("array", {big_numbers.begin(), big_numbers.end()})
32 | .set_payload_claim("object", from_raw_json)
33 | .sign(jwt::algorithm::none{});
34 | const auto decoded = jwt::decode(token);
35 |
36 | const auto array = traits::as_array(decoded.get_payload_claim("object").to_json()["api"]["array"]);
37 | std::cout << "payload /object/api/array = " << array << '\n';
38 |
39 | jwt::verify()
40 | .allow_algorithm(jwt::algorithm::none{})
41 | .with_issuer("auth.mydomain.io")
42 | .with_audience("mydomain.io")
43 | .with_claim("object", from_raw_json)
44 | .verify(decoded);
45 |
46 | return 0;
47 | }
48 |
--------------------------------------------------------------------------------
/include/jwt-cpp/traits/boost-json/defaults.h:
--------------------------------------------------------------------------------
1 | #ifndef JWT_CPP_BOOST_JSON_DEFAULTS_H
2 | #define JWT_CPP_BOOST_JSON_DEFAULTS_H
3 |
4 | #ifndef JWT_DISABLE_PICOJSON
5 | #define JWT_DISABLE_PICOJSON
6 | #endif
7 |
8 | #include "traits.h"
9 |
10 | namespace jwt {
11 | /**
12 | * \brief a class to store a generic [Boost.JSON](https://github.com/boostorg/json) value as claim
13 | *
14 | * This type is the specialization of the \ref basic_claim class which
15 | * uses the standard template types.
16 | */
17 | using claim = basic_claim;
18 |
19 | /**
20 | * Create a verifier using the default clock
21 | * \return verifier instance
22 | */
23 | inline verifier verify() {
24 | return verify(default_clock{});
25 | }
26 |
27 | /**
28 | * Create a builder using the default clock
29 | * \return builder instance to create a new token
30 | */
31 | inline builder create() {
32 | return builder(default_clock{});
33 | }
34 |
35 | #ifndef JWT_DISABLE_BASE64
36 | /**
37 | * Decode a token
38 | * \param token Token to decode
39 | * \return Decoded token
40 | * \throw std::invalid_argument Token is not in correct format
41 | * \throw std::runtime_error Base64 decoding failed or invalid json
42 | */
43 | inline decoded_jwt decode(const std::string& token) {
44 | return decoded_jwt(token);
45 | }
46 | #endif
47 |
48 | /**
49 | * Decode a token
50 | * \tparam Decode is callable, taking a string_type and returns a string_type.
51 | * It should ensure the padding of the input and then base64url decode and
52 | * return the results.
53 | * \param token Token to decode
54 | * \param decode The token to parse
55 | * \return Decoded token
56 | * \throw std::invalid_argument Token is not in correct format
57 | * \throw std::runtime_error Base64 decoding failed or invalid json
58 | */
59 | template
60 | decoded_jwt decode(const std::string& token, Decode decode) {
61 | return decoded_jwt(token, decode);
62 | }
63 |
64 | /**
65 | * Parse a jwk
66 | * \param token JWK Token to parse
67 | * \return Parsed JWK
68 | * \throw std::runtime_error Token is not in correct format
69 | */
70 | inline jwk parse_jwk(const traits::boost_json::string_type& token) {
71 | return jwk(token);
72 | }
73 |
74 | /**
75 | * Parse a jwks
76 | * \param token JWKs Token to parse
77 | * \return Parsed JWKs
78 | * \throw std::runtime_error Token is not in correct format
79 | */
80 | inline jwks parse_jwks(const traits::boost_json::string_type& token) {
81 | return jwks(token);
82 | }
83 |
84 | /**
85 | * This type is the specialization of the \ref verify_ops::verify_context class which
86 | * uses the standard template types.
87 | */
88 | using verify_context = verify_ops::verify_context;
89 | } // namespace jwt
90 |
91 | #endif // JWT_CPP_BOOST_JSON_DEFAULTS_H
92 |
--------------------------------------------------------------------------------
/include/jwt-cpp/traits/boost-json/traits.h:
--------------------------------------------------------------------------------
1 | #ifndef JWT_CPP_BOOSTJSON_TRAITS_H
2 | #define JWT_CPP_BOOSTJSON_TRAITS_H
3 |
4 | #define JWT_DISABLE_PICOJSON
5 | #include "jwt-cpp/jwt.h"
6 |
7 | #include
8 | // if not boost JSON standalone then error...
9 |
10 | namespace jwt {
11 | /**
12 | * \brief Namespace containing all the json_trait implementations for a jwt::basic_claim.
13 | */
14 | namespace traits {
15 | namespace json = boost::json;
16 | /// basic_claim's JSON trait implementation for Boost.JSON
17 | struct boost_json {
18 | using value_type = json::value;
19 | using object_type = json::object;
20 | using array_type = json::array;
21 | using string_type = std::string;
22 | using number_type = double;
23 | using integer_type = std::int64_t;
24 | using boolean_type = bool;
25 |
26 | static jwt::json::type get_type(const value_type& val) {
27 | using jwt::json::type;
28 |
29 | if (val.kind() == json::kind::bool_) return type::boolean;
30 | if (val.kind() == json::kind::int64) return type::integer;
31 | if (val.kind() == json::kind::uint64) // boost internally tracks two types of integers
32 | return type::integer;
33 | if (val.kind() == json::kind::double_) return type::number;
34 | if (val.kind() == json::kind::string) return type::string;
35 | if (val.kind() == json::kind::array) return type::array;
36 | if (val.kind() == json::kind::object) return type::object;
37 |
38 | throw std::logic_error("invalid type");
39 | }
40 |
41 | static object_type as_object(const value_type& val) {
42 | if (val.kind() != json::kind::object) throw std::bad_cast();
43 | return val.get_object();
44 | }
45 |
46 | static array_type as_array(const value_type& val) {
47 | if (val.kind() != json::kind::array) throw std::bad_cast();
48 | return val.get_array();
49 | }
50 |
51 | static string_type as_string(const value_type& val) {
52 | if (val.kind() != json::kind::string) throw std::bad_cast();
53 | return string_type{val.get_string()};
54 | }
55 |
56 | static integer_type as_integer(const value_type& val) {
57 | switch (val.kind()) {
58 | case json::kind::int64: return val.get_int64();
59 | case json::kind::uint64: return static_cast(val.get_uint64());
60 | default: throw std::bad_cast();
61 | }
62 | }
63 |
64 | static boolean_type as_boolean(const value_type& val) {
65 | if (val.kind() != json::kind::bool_) throw std::bad_cast();
66 | return val.get_bool();
67 | }
68 |
69 | static number_type as_number(const value_type& val) {
70 | if (val.kind() != json::kind::double_) throw std::bad_cast();
71 | return val.get_double();
72 | }
73 |
74 | static bool parse(value_type& val, string_type str) {
75 | val = json::parse(str);
76 | return true;
77 | }
78 |
79 | static std::string serialize(const value_type& val) { return json::serialize(val); }
80 | };
81 | } // namespace traits
82 | } // namespace jwt
83 |
84 | #endif // JWT_CPP_BOOSTJSON_TRAITS_H
85 |
--------------------------------------------------------------------------------
/include/jwt-cpp/traits/danielaparker-jsoncons/defaults.h:
--------------------------------------------------------------------------------
1 | #ifndef JWT_CPP_DANIELAPARKER_JSONCONS_DEFAULTS_H
2 | #define JWT_CPP_DANIELAPARKER_JSONCONS_DEFAULTS_H
3 |
4 | #ifndef JWT_DISABLE_PICOJSON
5 | #define JWT_DISABLE_PICOJSON
6 | #endif
7 |
8 | #include "traits.h"
9 |
10 | namespace jwt {
11 | /**
12 | * \brief a class to store a generic [jsoncons](https://github.com/danielaparker/jsoncons) value as claim
13 | *
14 | * This type is the specialization of the \ref basic_claim class which
15 | * uses the standard template types.
16 | */
17 | using claim = basic_claim;
18 |
19 | /**
20 | * Create a verifier using the default clock
21 | * \return verifier instance
22 | */
23 | inline verifier verify() {
24 | return verify(default_clock{});
25 | }
26 |
27 | /**
28 | * Create a builder using the default clock
29 | * \return builder instance to create a new token
30 | */
31 | inline builder create() {
32 | return builder(default_clock{});
33 | }
34 |
35 | #ifndef JWT_DISABLE_BASE64
36 | /**
37 | * Decode a token
38 | * \param token Token to decode
39 | * \return Decoded token
40 | * \throw std::invalid_argument Token is not in correct format
41 | * \throw std::runtime_error Base64 decoding failed or invalid json
42 | */
43 | inline decoded_jwt decode(const std::string& token) {
44 | return decoded_jwt(token);
45 | }
46 | #endif
47 |
48 | /**
49 | * Decode a token
50 | * \tparam Decode is callable, taking a string_type and returns a string_type.
51 | * It should ensure the padding of the input and then base64url decode and
52 | * return the results.
53 | * \param token Token to decode
54 | * \param decode The token to parse
55 | * \return Decoded token
56 | * \throw std::invalid_argument Token is not in correct format
57 | * \throw std::runtime_error Base64 decoding failed or invalid json
58 | */
59 | template
60 | decoded_jwt decode(const std::string& token, Decode decode) {
61 | return decoded_jwt(token, decode);
62 | }
63 |
64 | /**
65 | * Parse a jwk
66 | * \param token JWK Token to parse
67 | * \return Parsed JWK
68 | * \throw std::runtime_error Token is not in correct format
69 | */
70 | inline jwk parse_jwk(const traits::danielaparker_jsoncons::string_type& token) {
71 | return jwk(token);
72 | }
73 |
74 | /**
75 | * Parse a jwks
76 | * \param token JWKs Token to parse
77 | * \return Parsed JWKs
78 | * \throw std::runtime_error Token is not in correct format
79 | */
80 | inline jwks parse_jwks(const traits::danielaparker_jsoncons::string_type& token) {
81 | return jwks(token);
82 | }
83 |
84 | /**
85 | * This type is the specialization of the \ref verify_ops::verify_context class which
86 | * uses the standard template types.
87 | */
88 | using verify_context = verify_ops::verify_context;
89 | } // namespace jwt
90 |
91 | #endif // JWT_CPP_DANIELAPARKER_JSONCONS_DEFAULTS_H
92 |
--------------------------------------------------------------------------------
/include/jwt-cpp/traits/defaults.h.mustache:
--------------------------------------------------------------------------------
1 | #ifndef JWT_CPP_{{traits_name_upper}}_DEFAULTS_H
2 | #define JWT_CPP_{{traits_name_upper}}_DEFAULTS_H
3 | {{#disable_default_traits}}
4 |
5 | #ifndef JWT_DISABLE_PICOJSON
6 | #define JWT_DISABLE_PICOJSON
7 | #endif
8 | {{/disable_default_traits}}
9 |
10 | #include "traits.h"
11 |
12 | namespace jwt {
13 | /**
14 | * \brief a class to store a generic [{{library_name}}]({{{library_url}}}) value as claim
15 | *
16 | * This type is the specialization of the \ref basic_claim class which
17 | * uses the standard template types.
18 | */
19 | using claim = basic_claim;
20 |
21 | /**
22 | * Create a verifier using the default clock
23 | * \return verifier instance
24 | */
25 | inline verifier verify() {
26 | return verify(default_clock{});
27 | }
28 |
29 | /**
30 | * Create a builder using the default clock
31 | * \return builder instance to create a new token
32 | */
33 | inline builder create() {
34 | return builder(default_clock{});
35 | }
36 |
37 | #ifndef JWT_DISABLE_BASE64
38 | /**
39 | * Decode a token
40 | * \param token Token to decode
41 | * \return Decoded token
42 | * \throw std::invalid_argument Token is not in correct format
43 | * \throw std::runtime_error Base64 decoding failed or invalid json
44 | */
45 | inline decoded_jwt decode(const std::string& token) {
46 | return decoded_jwt(token);
47 | }
48 | #endif
49 |
50 | /**
51 | * Decode a token
52 | * \tparam Decode is callable, taking a string_type and returns a string_type.
53 | * It should ensure the padding of the input and then base64url decode and
54 | * return the results.
55 | * \param token Token to decode
56 | * \param decode The token to parse
57 | * \return Decoded token
58 | * \throw std::invalid_argument Token is not in correct format
59 | * \throw std::runtime_error Base64 decoding failed or invalid json
60 | */
61 | template
62 | decoded_jwt decode(const std::string& token, Decode decode) {
63 | return decoded_jwt(token, decode);
64 | }
65 |
66 | /**
67 | * Parse a jwk
68 | * \param token JWK Token to parse
69 | * \return Parsed JWK
70 | * \throw std::runtime_error Token is not in correct format
71 | */
72 | inline jwk parse_jwk(const traits::{{traits_name}}::string_type& token) {
73 | return jwk(token);
74 | }
75 |
76 | /**
77 | * Parse a jwks
78 | * \param token JWKs Token to parse
79 | * \return Parsed JWKs
80 | * \throw std::runtime_error Token is not in correct format
81 | */
82 | inline jwks parse_jwks(const traits::{{traits_name}}::string_type& token) {
83 | return jwks(token);
84 | }
85 |
86 | /**
87 | * This type is the specialization of the \ref verify_ops::verify_context class which
88 | * uses the standard template types.
89 | */
90 | using verify_context = verify_ops::verify_context;
91 | } // namespace jwt
92 |
93 | #endif // JWT_CPP_{{traits_name_upper}}_DEFAULTS_H
94 |
--------------------------------------------------------------------------------
/include/jwt-cpp/traits/kazuho-picojson/defaults.h:
--------------------------------------------------------------------------------
1 | #ifndef JWT_CPP_KAZUHO_PICOJSON_DEFAULTS_H
2 | #define JWT_CPP_KAZUHO_PICOJSON_DEFAULTS_H
3 |
4 | #include "traits.h"
5 |
6 | namespace jwt {
7 | /**
8 | * \brief a class to store a generic [picojson](https://github.com/kazuho/picojson) value as claim
9 | *
10 | * This type is the specialization of the \ref basic_claim class which
11 | * uses the standard template types.
12 | */
13 | using claim = basic_claim;
14 |
15 | /**
16 | * Create a verifier using the default clock
17 | * \return verifier instance
18 | */
19 | inline verifier verify() {
20 | return verify(default_clock{});
21 | }
22 |
23 | /**
24 | * Create a builder using the default clock
25 | * \return builder instance to create a new token
26 | */
27 | inline builder create() {
28 | return builder(default_clock{});
29 | }
30 |
31 | #ifndef JWT_DISABLE_BASE64
32 | /**
33 | * Decode a token
34 | * \param token Token to decode
35 | * \return Decoded token
36 | * \throw std::invalid_argument Token is not in correct format
37 | * \throw std::runtime_error Base64 decoding failed or invalid json
38 | */
39 | inline decoded_jwt decode(const std::string& token) {
40 | return decoded_jwt(token);
41 | }
42 | #endif
43 |
44 | /**
45 | * Decode a token
46 | * \tparam Decode is callable, taking a string_type and returns a string_type.
47 | * It should ensure the padding of the input and then base64url decode and
48 | * return the results.
49 | * \param token Token to decode
50 | * \param decode The token to parse
51 | * \return Decoded token
52 | * \throw std::invalid_argument Token is not in correct format
53 | * \throw std::runtime_error Base64 decoding failed or invalid json
54 | */
55 | template
56 | decoded_jwt decode(const std::string& token, Decode decode) {
57 | return decoded_jwt(token, decode);
58 | }
59 |
60 | /**
61 | * Parse a jwk
62 | * \param token JWK Token to parse
63 | * \return Parsed JWK
64 | * \throw std::runtime_error Token is not in correct format
65 | */
66 | inline jwk parse_jwk(const traits::kazuho_picojson::string_type& token) {
67 | return jwk(token);
68 | }
69 |
70 | /**
71 | * Parse a jwks
72 | * \param token JWKs Token to parse
73 | * \return Parsed JWKs
74 | * \throw std::runtime_error Token is not in correct format
75 | */
76 | inline jwks parse_jwks(const traits::kazuho_picojson::string_type& token) {
77 | return jwks(token);
78 | }
79 |
80 | /**
81 | * This type is the specialization of the \ref verify_ops::verify_context class which
82 | * uses the standard template types.
83 | */
84 | using verify_context = verify_ops::verify_context;
85 | } // namespace jwt
86 |
87 | #endif // JWT_CPP_KAZUHO_PICOJSON_DEFAULTS_H
88 |
--------------------------------------------------------------------------------
/include/jwt-cpp/traits/kazuho-picojson/traits.h:
--------------------------------------------------------------------------------
1 | #ifndef JWT_CPP_PICOJSON_TRAITS_H
2 | #define JWT_CPP_PICOJSON_TRAITS_H
3 |
4 | #ifndef PICOJSON_USE_INT64
5 | #define PICOJSON_USE_INT64
6 | #endif
7 | #include "picojson/picojson.h"
8 |
9 | #ifndef JWT_DISABLE_PICOJSON
10 | #define JWT_DISABLE_PICOJSON
11 | #endif
12 | #include "jwt-cpp/jwt.h"
13 |
14 | namespace jwt {
15 | /**
16 | * \brief Namespace containing all the json_trait implementations for a jwt::basic_claim.
17 | */
18 | namespace traits {
19 | /// basic_claim's JSON trait implementation for picojson
20 | struct kazuho_picojson {
21 | using value_type = picojson::value;
22 | using object_type = picojson::object;
23 | using array_type = picojson::array;
24 | using string_type = std::string;
25 | using number_type = double;
26 | using integer_type = int64_t;
27 | using boolean_type = bool;
28 |
29 | static json::type get_type(const picojson::value& val) {
30 | using json::type;
31 | if (val.is()) return type::boolean;
32 | if (val.is()) return type::integer;
33 | if (val.is()) return type::number;
34 | if (val.is()) return type::string;
35 | if (val.is()) return type::array;
36 | if (val.is()) return type::object;
37 |
38 | throw std::logic_error("invalid type");
39 | }
40 |
41 | static picojson::object as_object(const picojson::value& val) {
42 | if (!val.is()) throw std::bad_cast();
43 | return val.get();
44 | }
45 |
46 | static std::string as_string(const picojson::value& val) {
47 | if (!val.is()) throw std::bad_cast();
48 | return val.get();
49 | }
50 |
51 | static picojson::array as_array(const picojson::value& val) {
52 | if (!val.is()) throw std::bad_cast();
53 | return val.get();
54 | }
55 |
56 | static int64_t as_integer(const picojson::value& val) {
57 | if (!val.is()) throw std::bad_cast();
58 | return val.get();
59 | }
60 |
61 | static bool as_boolean(const picojson::value& val) {
62 | if (!val.is()) throw std::bad_cast();
63 | return val.get();
64 | }
65 |
66 | static double as_number(const picojson::value& val) {
67 | if (!val.is()) throw std::bad_cast();
68 | return val.get();
69 | }
70 |
71 | static bool parse(picojson::value& val, const std::string& str) {
72 | return picojson::parse(val, str).empty();
73 | }
74 |
75 | static std::string serialize(const picojson::value& val) { return val.serialize(); }
76 | };
77 | } // namespace traits
78 | } // namespace jwt
79 |
80 | #endif
81 |
--------------------------------------------------------------------------------
/include/jwt-cpp/traits/nlohmann-json/defaults.h:
--------------------------------------------------------------------------------
1 | #ifndef JWT_CPP_NLOHMANN_JSON_DEFAULTS_H
2 | #define JWT_CPP_NLOHMANN_JSON_DEFAULTS_H
3 |
4 | #ifndef JWT_DISABLE_PICOJSON
5 | #define JWT_DISABLE_PICOJSON
6 | #endif
7 |
8 | #include "traits.h"
9 |
10 | namespace jwt {
11 | /**
12 | * \brief a class to store a generic [JSON for Modern C++](https://github.com/nlohmann/json) value as claim
13 | *
14 | * This type is the specialization of the \ref basic_claim class which
15 | * uses the standard template types.
16 | */
17 | using claim = basic_claim;
18 |
19 | /**
20 | * Create a verifier using the default clock
21 | * \return verifier instance
22 | */
23 | inline verifier verify() {
24 | return verify(default_clock{});
25 | }
26 |
27 | /**
28 | * Create a builder using the default clock
29 | * \return builder instance to create a new token
30 | */
31 | inline builder create() {
32 | return builder(default_clock{});
33 | }
34 |
35 | #ifndef JWT_DISABLE_BASE64
36 | /**
37 | * Decode a token
38 | * \param token Token to decode
39 | * \return Decoded token
40 | * \throw std::invalid_argument Token is not in correct format
41 | * \throw std::runtime_error Base64 decoding failed or invalid json
42 | */
43 | inline decoded_jwt decode(const std::string& token) {
44 | return decoded_jwt(token);
45 | }
46 | #endif
47 |
48 | /**
49 | * Decode a token
50 | * \tparam Decode is callable, taking a string_type and returns a string_type.
51 | * It should ensure the padding of the input and then base64url decode and
52 | * return the results.
53 | * \param token Token to decode
54 | * \param decode The token to parse
55 | * \return Decoded token
56 | * \throw std::invalid_argument Token is not in correct format
57 | * \throw std::runtime_error Base64 decoding failed or invalid json
58 | */
59 | template
60 | decoded_jwt decode(const std::string& token, Decode decode) {
61 | return decoded_jwt(token, decode);
62 | }
63 |
64 | /**
65 | * Parse a jwk
66 | * \param token JWK Token to parse
67 | * \return Parsed JWK
68 | * \throw std::runtime_error Token is not in correct format
69 | */
70 | inline jwk parse_jwk(const traits::nlohmann_json::string_type& token) {
71 | return jwk(token);
72 | }
73 |
74 | /**
75 | * Parse a jwks
76 | * \param token JWKs Token to parse
77 | * \return Parsed JWKs
78 | * \throw std::runtime_error Token is not in correct format
79 | */
80 | inline jwks parse_jwks(const traits::nlohmann_json::string_type& token) {
81 | return jwks(token);
82 | }
83 |
84 | /**
85 | * This type is the specialization of the \ref verify_ops::verify_context class which
86 | * uses the standard template types.
87 | */
88 | using verify_context = verify_ops::verify_context;
89 | } // namespace jwt
90 |
91 | #endif // JWT_CPP_NLOHMANN_JSON_DEFAULTS_H
92 |
--------------------------------------------------------------------------------
/include/jwt-cpp/traits/nlohmann-json/traits.h:
--------------------------------------------------------------------------------
1 | #ifndef JWT_CPP_NLOHMANN_JSON_TRAITS_H
2 | #define JWT_CPP_NLOHMANN_JSON_TRAITS_H
3 |
4 | #include "jwt-cpp/jwt.h"
5 | #include "nlohmann/json.hpp"
6 |
7 | namespace jwt {
8 | /**
9 | * \brief Namespace containing all the json_trait implementations for a jwt::basic_claim.
10 | */
11 | namespace traits {
12 | /// basic_claim's JSON trait implementation for Modern C++ JSON
13 | struct nlohmann_json {
14 | using json = nlohmann::json;
15 | using value_type = json;
16 | using object_type = json::object_t;
17 | using array_type = json::array_t;
18 | using string_type = std::string; // current limitation of traits implementation
19 | using number_type = json::number_float_t;
20 | using integer_type = json::number_integer_t;
21 | using boolean_type = json::boolean_t;
22 |
23 | static jwt::json::type get_type(const json& val) {
24 | using jwt::json::type;
25 |
26 | if (val.type() == json::value_t::boolean) return type::boolean;
27 | // nlohmann internally tracks two types of integers
28 | if (val.type() == json::value_t::number_integer) return type::integer;
29 | if (val.type() == json::value_t::number_unsigned) return type::integer;
30 | if (val.type() == json::value_t::number_float) return type::number;
31 | if (val.type() == json::value_t::string) return type::string;
32 | if (val.type() == json::value_t::array) return type::array;
33 | if (val.type() == json::value_t::object) return type::object;
34 |
35 | throw std::logic_error("invalid type");
36 | }
37 |
38 | static json::object_t as_object(const json& val) {
39 | if (val.type() != json::value_t::object) throw std::bad_cast();
40 | return val.get();
41 | }
42 |
43 | static std::string as_string(const json& val) {
44 | if (val.type() != json::value_t::string) throw std::bad_cast();
45 | return val.get();
46 | }
47 |
48 | static json::array_t as_array(const json& val) {
49 | if (val.type() != json::value_t::array) throw std::bad_cast();
50 | return val.get();
51 | }
52 |
53 | static int64_t as_integer(const json& val) {
54 | switch (val.type()) {
55 | case json::value_t::number_integer:
56 | case json::value_t::number_unsigned: return val.get();
57 | default: throw std::bad_cast();
58 | }
59 | }
60 |
61 | static bool as_boolean(const json& val) {
62 | if (val.type() != json::value_t::boolean) throw std::bad_cast();
63 | return val.get();
64 | }
65 |
66 | static double as_number(const json& val) {
67 | if (val.type() != json::value_t::number_float) throw std::bad_cast();
68 | return val.get();
69 | }
70 |
71 | static bool parse(json& val, std::string str) {
72 | val = json::parse(str.begin(), str.end());
73 | return true;
74 | }
75 |
76 | static std::string serialize(const json& val) { return val.dump(); }
77 | };
78 | } // namespace traits
79 | } // namespace jwt
80 |
81 | #endif
82 |
--------------------------------------------------------------------------------
/include/jwt-cpp/traits/open-source-parsers-jsoncpp/defaults.h:
--------------------------------------------------------------------------------
1 | #ifndef JWT_CPP_OPEN_SOURCE_PARSERS_JSONCPP_DEFAULTS_H
2 | #define JWT_CPP_OPEN_SOURCE_PARSERS_JSONCPP_DEFAULTS_H
3 |
4 | #ifndef JWT_DISABLE_PICOJSON
5 | #define JWT_DISABLE_PICOJSON
6 | #endif
7 |
8 | #include "traits.h"
9 |
10 | namespace jwt {
11 | /**
12 | * \brief a class to store a generic [jsoncpp](https://github.com/open-source-parsers/jsoncpp) value as claim
13 | *
14 | * This type is the specialization of the \ref basic_claim class which
15 | * uses the standard template types.
16 | */
17 | using claim = basic_claim;
18 |
19 | /**
20 | * Create a verifier using the default clock
21 | * \return verifier instance
22 | */
23 | inline verifier verify() {
24 | return verify(default_clock{});
25 | }
26 |
27 | /**
28 | * Create a builder using the default clock
29 | * \return builder instance to create a new token
30 | */
31 | inline builder create() {
32 | return builder(default_clock{});
33 | }
34 |
35 | #ifndef JWT_DISABLE_BASE64
36 | /**
37 | * Decode a token
38 | * \param token Token to decode
39 | * \return Decoded token
40 | * \throw std::invalid_argument Token is not in correct format
41 | * \throw std::runtime_error Base64 decoding failed or invalid json
42 | */
43 | inline decoded_jwt decode(const std::string& token) {
44 | return decoded_jwt(token);
45 | }
46 | #endif
47 |
48 | /**
49 | * Decode a token
50 | * \tparam Decode is callable, taking a string_type and returns a string_type.
51 | * It should ensure the padding of the input and then base64url decode and
52 | * return the results.
53 | * \param token Token to decode
54 | * \param decode The token to parse
55 | * \return Decoded token
56 | * \throw std::invalid_argument Token is not in correct format
57 | * \throw std::runtime_error Base64 decoding failed or invalid json
58 | */
59 | template
60 | decoded_jwt decode(const std::string& token, Decode decode) {
61 | return decoded_jwt(token, decode);
62 | }
63 |
64 | /**
65 | * Parse a jwk
66 | * \param token JWK Token to parse
67 | * \return Parsed JWK
68 | * \throw std::runtime_error Token is not in correct format
69 | */
70 | inline jwk
71 | parse_jwk(const traits::open_source_parsers_jsoncpp::string_type& token) {
72 | return jwk(token);
73 | }
74 |
75 | /**
76 | * Parse a jwks
77 | * \param token JWKs Token to parse
78 | * \return Parsed JWKs
79 | * \throw std::runtime_error Token is not in correct format
80 | */
81 | inline jwks
82 | parse_jwks(const traits::open_source_parsers_jsoncpp::string_type& token) {
83 | return jwks(token);
84 | }
85 |
86 | /**
87 | * This type is the specialization of the \ref verify_ops::verify_context class which
88 | * uses the standard template types.
89 | */
90 | using verify_context = verify_ops::verify_context;
91 | } // namespace jwt
92 |
93 | #endif // JWT_CPP_OPEN_SOURCE_PARSERS_JSONCPP_DEFAULTS_H
94 |
--------------------------------------------------------------------------------
/include/jwt-cpp/traits/open-source-parsers-jsoncpp/traits.h:
--------------------------------------------------------------------------------
1 | #ifndef JWT_CPP_JSONCPP_TRAITS_H
2 | #define JWT_CPP_JSONCPP_TRAITS_H
3 |
4 | #include "jwt-cpp/jwt.h"
5 | #include "json/json.h"
6 |
7 | namespace jwt {
8 | /**
9 | * \brief Namespace containing all the json_trait implementations for a jwt::basic_claim.
10 | */
11 | namespace traits {
12 | /// basic_claim's JSON trait implementation for jsoncpp
13 | struct open_source_parsers_jsoncpp {
14 | using value_type = Json::Value;
15 | using string_type = std::string;
16 | class array_type : public Json::Value {
17 | public:
18 | using value_type = Json::Value;
19 |
20 | array_type() = default;
21 | array_type(const array_type&) = default;
22 | explicit array_type(const Json::Value& o) : Json::Value(o) {}
23 | array_type(array_type&&) = default;
24 | explicit array_type(Json::Value&& o) : Json::Value(o) {}
25 | template
26 | array_type(Iterator begin, Iterator end) {
27 | for (Iterator it = begin; it != end; ++it) {
28 | Json::Value value;
29 | value = *it;
30 | this->append(value);
31 | }
32 | }
33 | ~array_type() = default;
34 | array_type& operator=(const array_type& o) = default;
35 | array_type& operator=(array_type&& o) noexcept = default;
36 |
37 | value_type const& front() const { return this->operator[](0U); }
38 | };
39 | using number_type = double;
40 | using integer_type = Json::Value::Int;
41 | using boolean_type = bool;
42 | class object_type : public Json::Value {
43 | public:
44 | using key_type = std::string;
45 | using mapped_type = Json::Value;
46 | using size_type = size_t;
47 |
48 | object_type() = default;
49 | object_type(const object_type&) = default;
50 | explicit object_type(const Json::Value& o) : Json::Value(o) {}
51 | object_type(object_type&&) = default;
52 | explicit object_type(Json::Value&& o) : Json::Value(o) {}
53 | ~object_type() = default;
54 | object_type& operator=(const object_type& o) = default;
55 | object_type& operator=(object_type&& o) noexcept = default;
56 |
57 | // Add missing C++11 element access
58 | const mapped_type& at(const key_type& key) const {
59 | Json::Value const* found = find(key.data(), key.data() + key.length());
60 | if (!found) throw std::out_of_range("invalid key");
61 | return *found;
62 | }
63 |
64 | size_type count(const key_type& key) const { return this->isMember(key) ? 1 : 0; }
65 | };
66 |
67 | // Translation between the implementation notion of type, to the jwt::json::type equivilant
68 | static jwt::json::type get_type(const value_type& val) {
69 | using jwt::json::type;
70 |
71 | if (val.isArray())
72 | return type::array;
73 | else if (val.isString())
74 | return type::string;
75 | // Order is important https://github.com/Thalhammer/jwt-cpp/pull/320#issuecomment-1865322511
76 | else if (val.isInt())
77 | return type::integer;
78 | else if (val.isNumeric())
79 | return type::number;
80 | else if (val.isBool())
81 | return type::boolean;
82 | else if (val.isObject())
83 | return type::object;
84 |
85 | throw std::logic_error("invalid type");
86 | }
87 |
88 | static integer_type as_integer(const value_type& val) {
89 | switch (val.type()) {
90 | case Json::intValue: return val.asInt64();
91 | case Json::uintValue: return static_cast(val.asUInt64());
92 | default: throw std::bad_cast();
93 | }
94 | }
95 |
96 | static boolean_type as_boolean(const value_type& val) {
97 | if (!val.isBool()) throw std::bad_cast();
98 | return val.asBool();
99 | }
100 |
101 | static number_type as_number(const value_type& val) {
102 | if (!val.isNumeric()) throw std::bad_cast();
103 | return val.asDouble();
104 | }
105 |
106 | static string_type as_string(const value_type& val) {
107 | if (!val.isString()) throw std::bad_cast();
108 | return val.asString();
109 | }
110 |
111 | static object_type as_object(const value_type& val) {
112 | if (!val.isObject()) throw std::bad_cast();
113 | return object_type(val);
114 | }
115 |
116 | static array_type as_array(const value_type& val) {
117 | if (!val.isArray()) throw std::bad_cast();
118 | return array_type(val);
119 | }
120 |
121 | static bool parse(value_type& val, string_type str) {
122 | Json::CharReaderBuilder builder;
123 | const std::unique_ptr reader(builder.newCharReader());
124 |
125 | return reader->parse(reinterpret_cast(str.c_str()),
126 | reinterpret_cast(str.c_str() + str.size()), &val, nullptr);
127 | }
128 |
129 | static string_type serialize(const value_type& val) {
130 | Json::StreamWriterBuilder builder;
131 | builder["commentStyle"] = "None";
132 | builder["indentation"] = "";
133 | std::unique_ptr writer(builder.newStreamWriter());
134 | return Json::writeString(builder, val);
135 | }
136 | };
137 | } // namespace traits
138 | } // namespace jwt
139 |
140 | #endif
141 |
--------------------------------------------------------------------------------
/nuget/jwt-cpp.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | jwt-cpp
5 | 0.7.1
6 | Thalhammer; prince-chrismc
7 | Thalhammer; prince-chrismc
8 | https://github.com/Thalhammer/jwt-cpp
9 | JWT++ is a header only library for creating and validating JSON Web Tokens in C++11. This library supports all the algorithms defined by the JWT specifications, and the modular design allows to easily add additional algorithms without any problems. In the name of flexibility and extensibility, jwt-cpp supports OpenSSL, LibreSSL, and wolfSSL. And there is no hard dependency on a JSON library.
10 |
11 | Supporting OpenSSL 3.0.0, WolfSSL, Hunter CMake, Boost.JSON, JWKs, ES256K.
12 | MIT
13 | Copyright (c) 2018 Dominik Thalhammer
14 | JWT++: JSON Web Tokens in C++11
15 | JWT++; a header only library for creating and validating JSON Web Tokens in C++11.
16 | JWT, json, web, token, C++, header-only
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/nuget/jwt-cpp.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | $(MSBuildThisFileDirectory)..\..\lib\native\include\;%(AdditionalIncludeDirectories)
6 |
7 |
8 |
--------------------------------------------------------------------------------
/tests/BaseTest.cpp:
--------------------------------------------------------------------------------
1 | #include "jwt-cpp/base.h"
2 | #include
3 |
4 | TEST(BaseTest, Base64Index) {
5 | ASSERT_EQ(0, jwt::alphabet::index(jwt::alphabet::base64::rdata(), 'A'));
6 | ASSERT_EQ(32, jwt::alphabet::index(jwt::alphabet::base64::rdata(), 'g'));
7 | ASSERT_EQ(62, jwt::alphabet::index(jwt::alphabet::base64::rdata(), '+'));
8 |
9 | std::size_t index = 0;
10 | for (auto c : jwt::alphabet::base64::data()) {
11 | ASSERT_EQ(index, jwt::alphabet::index(jwt::alphabet::base64::rdata(), c));
12 | index++;
13 | }
14 |
15 | std::size_t noBaseCharCount = 0;
16 | for (std::size_t i = 0; i < jwt::alphabet::base64::rdata().size(); i++) {
17 | if (jwt::alphabet::base64::rdata().at(i) == -1) { noBaseCharCount++; }
18 | }
19 | ASSERT_EQ(jwt::alphabet::base64::rdata().size() - jwt::alphabet::base64::data().size(), noBaseCharCount);
20 | }
21 |
22 | TEST(BaseTest, Base64URLIndex) {
23 | ASSERT_EQ(0, jwt::alphabet::index(jwt::alphabet::base64url::rdata(), 'A'));
24 | ASSERT_EQ(32, jwt::alphabet::index(jwt::alphabet::base64url::rdata(), 'g'));
25 | ASSERT_EQ(62, jwt::alphabet::index(jwt::alphabet::base64url::rdata(), '-'));
26 |
27 | std::size_t index = 0;
28 | for (auto c : jwt::alphabet::base64url::data()) {
29 | ASSERT_EQ(index, jwt::alphabet::index(jwt::alphabet::base64url::rdata(), c));
30 | index++;
31 | }
32 |
33 | std::size_t noBaseCharCount = 0;
34 | for (std::size_t i = 0; i < jwt::alphabet::base64url::rdata().size(); i++) {
35 | if (jwt::alphabet::base64url::rdata().at(i) == -1) { noBaseCharCount++; }
36 | }
37 | ASSERT_EQ(jwt::alphabet::base64url::rdata().size() - jwt::alphabet::base64url::data().size(), noBaseCharCount);
38 | }
39 |
40 | TEST(BaseTest, BaseDetailsCountPadding) {
41 | using jwt::base::details::padding;
42 | ASSERT_EQ(padding{}, jwt::base::details::count_padding("ABC", {"~"}));
43 | ASSERT_EQ((padding{3, 3}), jwt::base::details::count_padding("ABC~~~", {"~"}));
44 | ASSERT_EQ((padding{5, 5}), jwt::base::details::count_padding("ABC~~~~~", {"~"}));
45 |
46 | ASSERT_EQ(padding{}, jwt::base::details::count_padding("ABC", {"~", "!"}));
47 | ASSERT_EQ((padding{1, 1}), jwt::base::details::count_padding("ABC!", {"~", "!"}));
48 | ASSERT_EQ((padding{1, 1}), jwt::base::details::count_padding("ABC~", {"~", "!"}));
49 | ASSERT_EQ((padding{3, 3}), jwt::base::details::count_padding("ABC~~!", {"~", "!"}));
50 | ASSERT_EQ((padding{3, 3}), jwt::base::details::count_padding("ABC!~~", {"~", "!"}));
51 | ASSERT_EQ((padding{5, 5}), jwt::base::details::count_padding("ABC~~!~~", {"~", "!"}));
52 |
53 | ASSERT_EQ((padding{2, 6}), jwt::base::details::count_padding("MTIzNA%3d%3d", {"%3d", "%3D"}));
54 | ASSERT_EQ((padding{2, 6}), jwt::base::details::count_padding("MTIzNA%3d%3D", {"%3d", "%3D"}));
55 | ASSERT_EQ((padding{2, 6}), jwt::base::details::count_padding("MTIzNA%3D%3d", {"%3d", "%3D"}));
56 | ASSERT_EQ((padding{2, 6}), jwt::base::details::count_padding("MTIzNA%3D%3D", {"%3d", "%3D"}));
57 |
58 | // Some fake scenarios
59 |
60 | ASSERT_EQ(padding{}, jwt::base::details::count_padding("", {"~"}));
61 | ASSERT_EQ(padding{}, jwt::base::details::count_padding("ABC", {"~", "~~!"}));
62 | ASSERT_EQ(padding{}, jwt::base::details::count_padding("ABC!", {"~", "~~!"}));
63 | ASSERT_EQ((padding{1, 1}), jwt::base::details::count_padding("ABC~", {"~", "~~!"}));
64 | ASSERT_EQ((padding{1, 3}), jwt::base::details::count_padding("ABC~~!", {"~", "~~!"}));
65 | ASSERT_EQ((padding{2, 2}), jwt::base::details::count_padding("ABC!~~", {"~", "~~!"}));
66 | ASSERT_EQ((padding{3, 5}), jwt::base::details::count_padding("ABC~~!~~", {"~", "~~!"}));
67 | ASSERT_EQ(padding{}, jwt::base::details::count_padding("ABC~~!~~", {}));
68 | }
69 |
70 | TEST(BaseTest, Base64Decode) {
71 | ASSERT_EQ("1", jwt::base::decode("MQ=="));
72 | ASSERT_EQ("12", jwt::base::decode("MTI="));
73 | ASSERT_EQ("123", jwt::base::decode("MTIz"));
74 | ASSERT_EQ("1234", jwt::base::decode("MTIzNA=="));
75 | }
76 |
77 | TEST(BaseTest, Base64DecodeURL) {
78 | ASSERT_EQ("1", jwt::base::decode("MQ%3d%3d"));
79 | ASSERT_EQ("12", jwt::base::decode("MTI%3d"));
80 | ASSERT_EQ("123", jwt::base::decode("MTIz"));
81 | ASSERT_EQ("1234", jwt::base::decode("MTIzNA%3d%3d"));
82 | }
83 |
84 | TEST(BaseTest, Base64DecodeURLCaseInsensitive) {
85 | ASSERT_EQ("1", jwt::base::decode("MQ%3d%3d"));
86 | ASSERT_EQ("1", jwt::base::decode("MQ%3D%3d"));
87 | ASSERT_EQ("1", jwt::base::decode("MQ%3d%3D"));
88 | ASSERT_EQ("12", jwt::base::decode("MTI%3d"));
89 | ASSERT_EQ("123", jwt::base::decode("MTIz"));
90 | ASSERT_EQ("1234", jwt::base::decode("MTIzNA%3d%3d"));
91 | ASSERT_EQ("1234", jwt::base::decode("MTIzNA%3D%3D"));
92 | }
93 |
94 | TEST(BaseTest, Base64Encode) {
95 | ASSERT_EQ("MQ==", jwt::base::encode("1"));
96 | ASSERT_EQ("MTI=", jwt::base::encode("12"));
97 | ASSERT_EQ("MTIz", jwt::base::encode("123"));
98 | ASSERT_EQ("MTIzNA==", jwt::base::encode("1234"));
99 | }
100 |
101 | TEST(BaseTest, Base64EncodeURL) {
102 | ASSERT_EQ("MQ%3d%3d", jwt::base::encode("1"));
103 | ASSERT_EQ("MTI%3d", jwt::base::encode("12"));
104 | ASSERT_EQ("MTIz", jwt::base::encode("123"));
105 | ASSERT_EQ("MTIzNA%3d%3d", jwt::base::encode("1234"));
106 | }
107 |
108 | TEST(BaseTest, Base64Pad) {
109 | ASSERT_EQ("MQ==", jwt::base::pad("MQ"));
110 | ASSERT_EQ("MTI=", jwt::base::pad("MTI"));
111 | ASSERT_EQ("MTIz", jwt::base::pad("MTIz"));
112 | ASSERT_EQ("MTIzNA==", jwt::base::pad("MTIzNA"));
113 | }
114 |
115 | TEST(BaseTest, Base64PadURL) {
116 | ASSERT_EQ("MQ%3d%3d", jwt::base::pad("MQ"));
117 | ASSERT_EQ("MTI%3d", jwt::base::pad("MTI"));
118 | ASSERT_EQ("MTIz", jwt::base::pad("MTIz"));
119 | ASSERT_EQ("MTIzNA%3d%3d", jwt::base::pad("MTIzNA"));
120 | }
121 |
122 | TEST(BaseTest, Base64Trim) {
123 | ASSERT_EQ("MQ", jwt::base::trim("MQ=="));
124 | ASSERT_EQ("MTI", jwt::base::trim("MTI="));
125 | ASSERT_EQ("MTIz", jwt::base::trim("MTIz"));
126 | ASSERT_EQ("MTIzNA", jwt::base::trim("MTIzNA=="));
127 | }
128 |
129 | TEST(BaseTest, Base64TrimURL) {
130 | ASSERT_EQ("MQ", jwt::base::trim("MQ%3d%3d"));
131 | ASSERT_EQ("MTI", jwt::base::trim("MTI%3d"));
132 | ASSERT_EQ("MTIz", jwt::base::trim("MTIz"));
133 | ASSERT_EQ("MTIzNA", jwt::base::trim("MTIzNA%3d%3d"));
134 | }
135 |
--------------------------------------------------------------------------------
/tests/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | if(JWT_DISABLE_BASE64)
2 | message(FATAL_ERROR "Tests requires the base64 support to be enabled!")
3 | endif()
4 |
5 | if(JWT_DISABLE_PICOJSON)
6 | message(FATAL_ERROR "Tests requires the picojson support to be enabled!")
7 | endif()
8 |
9 | include(GoogleTest)
10 | if(HUNTER_ENABLED)
11 | hunter_add_package(GTest)
12 | endif()
13 |
14 | find_package(GTest)
15 | if(NOT TARGET GTest::gtest_main)
16 | message(STATUS "jwt-cpp: using FetchContent for GTest")
17 | include(FetchContent)
18 | fetchcontent_declare(googletest
19 | URL https://github.com/google/googletest/archive/03597a01ee50ed33e9dfd640b249b4be3799d395.zip)
20 | # https://google.github.io/googletest/quickstart-cmake.html
21 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
22 | fetchcontent_makeavailable(googletest)
23 | endif()
24 |
25 | set(TEST_SOURCES
26 | ${CMAKE_CURRENT_SOURCE_DIR}/BaseTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/ClaimTest.cpp
27 | ${CMAKE_CURRENT_SOURCE_DIR}/Keys.cpp ${CMAKE_CURRENT_SOURCE_DIR}/HelperTest.cpp
28 | ${CMAKE_CURRENT_SOURCE_DIR}/TestMain.cpp ${CMAKE_CURRENT_SOURCE_DIR}/TokenFormatTest.cpp
29 | ${CMAKE_CURRENT_SOURCE_DIR}/TokenTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/JwksTest.cpp
30 | ${CMAKE_CURRENT_SOURCE_DIR}/OpenSSLErrorTest.cpp ${CMAKE_CURRENT_SOURCE_DIR}/traits/NlohmannTest.cpp)
31 |
32 | find_package(jsoncons CONFIG)
33 | if(TARGET jsoncons)
34 | list(APPEND TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/traits/JsonconsTest.cpp)
35 | endif()
36 |
37 | include("private-find-boost-json")
38 | if(TARGET boost_json)
39 | list(APPEND TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/traits/BoostJsonTest.cpp)
40 | endif()
41 |
42 | find_package(jsoncpp CONFIG)
43 | if(TARGET jsoncpp_static)
44 | list(APPEND TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/traits/OspJsoncppTest.cpp)
45 | endif()
46 |
47 | add_executable(jwt-cpp-test ${TEST_SOURCES})
48 |
49 | # NOTE: Don't use space inside a generator expression here, because the function prematurely breaks the expression into
50 | # multiple lines. https://cmake.org/pipermail/cmake/2018-April/067422.html
51 | set(JWT_TESTER_GCC_FLAGS -Wall -Wextra -Wpedantic -ggdb)
52 | set(JWT_TESTER_CLANG_FLAGS -Weverything -Wno-c++98-compat -Wno-global-constructors -Wno-weak-vtables)
53 | target_compile_options(
54 | jwt-cpp-test PRIVATE $<$:/W4> $<$:${JWT_TESTER_GCC_FLAGS}>
55 | $<$:${JWT_TESTER_CLANG_FLAGS}>)
56 | if(HUNTER_ENABLED)
57 | target_link_libraries(jwt-cpp-test PRIVATE GTest::gtest GTest::gtest_main)
58 | # Define a compile define to bypass openssl error tests
59 | target_compile_definitions(jwt-cpp-test PRIVATE HUNTER_ENABLED=1)
60 | else()
61 | # https://github.com/google/googletest/blob/eb80f759d595874a5e905a3342bd8e2af4c0a12d/googletest/README.md?plain=1#L62-L64
62 | target_link_libraries(jwt-cpp-test PRIVATE GTest::gtest_main)
63 | if(TARGET jsoncons)
64 | target_link_libraries(jwt-cpp-test PRIVATE jsoncons)
65 | endif()
66 | if(TARGET boost_json)
67 | target_link_libraries(jwt-cpp-test PRIVATE boost_json)
68 | endif()
69 | if(TARGET jsoncpp_static)
70 | target_link_libraries(jwt-cpp-test PRIVATE jsoncpp_static)
71 | endif()
72 | endif()
73 | target_link_libraries(jwt-cpp-test PRIVATE jwt-cpp nlohmann_json::nlohmann_json
74 | $<$>:${CMAKE_DL_LIBS}>)
75 |
76 | gtest_discover_tests(jwt-cpp-test)
77 | add_custom_target(jwt-cpp-test-run COMMAND jwt-cpp-test)
78 |
79 | if(JWT_ENABLE_COVERAGE)
80 | include("code-coverage")
81 | setup_coverage(jwt-cpp-test)
82 | set(COVERAGE_EXCLUDES "/usr/**" "/home/*/.conan/**" "*test*" "*build*" "**/nlohmann/json.hpp"
83 | "**/picojson/picojson.h" "*boost*" "*jsoncons*")
84 | setup_target_for_coverage_lcov(NAME coverage EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/jwt-cpp-test)
85 | endif()
86 |
--------------------------------------------------------------------------------
/tests/CMakePresets.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 6,
3 | "cmakeMinimumRequired": {
4 | "major": 3,
5 | "minor": 25,
6 | "patch": 0
7 | },
8 | "include": [
9 | "../cmake/CMakePresets.json"
10 | ],
11 | "configurePresets": [
12 | {
13 | "name": "linux",
14 | "hidden": true,
15 | "description": "This is only available on Linux",
16 | "condition": {
17 | "type": "equals",
18 | "lhs": "${hostSystemName}",
19 | "rhs": "Linux"
20 | }
21 | },
22 | {
23 | "name": "coverage",
24 | "inherits": ["debug", "linux"],
25 | "displayName": "Coverage",
26 | "description": "This is only available on Linux",
27 | "cacheVariables": {
28 | "JWT_BUILD_TESTS": "ON",
29 | "JWT_ENABLE_COVERAGE": "ON"
30 | }
31 | },
32 | {
33 | "name": "unit-tests",
34 | "inherits": ["debug"],
35 | "displayName": "Unit Tests",
36 | "cacheVariables": {
37 | "JWT_BUILD_TESTS": "ON"
38 | }
39 | },
40 | {
41 | "name": "ci-fuzzing",
42 | "inherits": ["debug", "linux"],
43 | "displayName": "Fuzz Testing",
44 | "description": "This is only available on Linux with Clang",
45 | "cacheVariables": {
46 | "JWT_ENABLE_FUZZING": "ON",
47 | "CMAKE_C_COMPILER": "clang",
48 | "CMAKE_CXX_COMPILER": "clang++"
49 | }
50 | },
51 | {
52 | "name": "ci-asan",
53 | "inherits": ["debug", "linux"],
54 | "displayName": "Address/Leak Sanitizer",
55 | "description": "This is only available on Linux",
56 | "environment": {
57 | "ASAN_FLAGS": "-fsanitize=address -fsanitize=leak",
58 | "ASAN_OPTIONS": "check_initialization_order=true:detect_stack_use_after_return=true:fast_unwind_on_malloc=0"
59 | },
60 | "cacheVariables": {
61 | "JWT_BUILD_EXAMPLES": "ON",
62 | "JWT_BUILD_TESTS": "ON",
63 | "CMAKE_C_FLAGS": "$env{ASAN_FLAGS}",
64 | "CMAKE_CXX_FLAGS": "$env{ASAN_FLAGS}",
65 | "CMAKE_EXE_LINKER_FLAGS": "$env{ASAN_FLAGS}",
66 | "CMAKE_MODULE_LINKER_FLAGS": "$env{ASAN_FLAGS}"
67 | }
68 | },
69 | {
70 | "name": "ci-ubsan",
71 | "inherits": ["debug", "linux"],
72 | "displayName": "Undefined Behavior Sanitizer",
73 | "description": "This is only available on Linux",
74 | "environment": {
75 | "UBSAN_FLAGS": "-fsanitize=undefined -fsanitize=return -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize-recover=all",
76 | "UBSAN_OPTIONS": "print_stacktrace=1"
77 | },
78 | "cacheVariables": {
79 | "JWT_BUILD_EXAMPLES": "ON",
80 | "JWT_BUILD_TESTS": "ON",
81 | "CMAKE_C_FLAGS": "$env{UBSAN_FLAGS}",
82 | "CMAKE_CXX_FLAGS": "$env{UBSAN_FLAGS}",
83 | "CMAKE_EXE_LINKER_FLAGS": "$env{UBSAN_FLAGS}",
84 | "CMAKE_MODULE_LINKER_FLAGS": "$env{UBSAN_FLAGS}"
85 | }
86 | }
87 | ],
88 | "buildPresets": [
89 | {
90 | "name": "coverage",
91 | "configurePreset": "coverage",
92 | "configuration": "Debug",
93 | "targets": [
94 | "jwt-cpp-test",
95 | "coverage"
96 | ]
97 | },
98 | {
99 | "name": "unit-tests",
100 | "configurePreset": "unit-tests",
101 | "configuration": "Debug",
102 | "targets": [
103 | "jwt-cpp-test"
104 | ]
105 | },
106 | {
107 | "name": "ci-fuzzing",
108 | "configurePreset": "ci-fuzzing",
109 | "targets": [
110 | "jwt-cpp-fuzz-BaseEncodeFuzz",
111 | "jwt-cpp-fuzz-BaseDecodeFuzz",
112 | "jwt-cpp-fuzz-TokenDecodeFuzz"
113 | ]
114 | },
115 | {
116 | "name": "ci-asan",
117 | "configurePreset": "ci-asan",
118 | "targets": [
119 | "rsa-create",
120 | "rsa-verify",
121 | "jwks-verify",
122 | "jwt-cpp-test"
123 | ]
124 | },
125 | {
126 | "name": "ci-ubsan",
127 | "configurePreset": "ci-ubsan",
128 | "targets": [
129 | "rsa-create",
130 | "rsa-verify",
131 | "jwks-verify",
132 | "jwt-cpp-test"
133 | ]
134 | }
135 | ],
136 | "testPresets": [
137 | {
138 | "name": "unit-tests",
139 | "description": "Run the unit tests",
140 | "configurePreset": "unit-tests",
141 | "execution": {
142 | "noTestsAction": "error"
143 | }
144 | }
145 | ]
146 | }
--------------------------------------------------------------------------------
/tests/ClaimTest.cpp:
--------------------------------------------------------------------------------
1 | #include "jwt-cpp/jwt.h"
2 | #include
3 |
4 | TEST(ClaimTest, AudienceAsString) {
5 | std::string const token =
6 | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ0ZXN0In0.WZnM3SIiSRHsbO3O7Z2bmIzTJ4EC32HRBKfLznHhrh4";
7 | auto decoded = jwt::decode(token);
8 |
9 | ASSERT_TRUE(decoded.has_algorithm());
10 | ASSERT_TRUE(decoded.has_type());
11 | ASSERT_FALSE(decoded.has_content_type());
12 | ASSERT_FALSE(decoded.has_key_id());
13 | ASSERT_FALSE(decoded.has_issuer());
14 | ASSERT_FALSE(decoded.has_subject());
15 | ASSERT_TRUE(decoded.has_audience());
16 | ASSERT_FALSE(decoded.has_expires_at());
17 | ASSERT_FALSE(decoded.has_not_before());
18 | ASSERT_FALSE(decoded.has_issued_at());
19 | ASSERT_FALSE(decoded.has_id());
20 |
21 | ASSERT_EQ("HS256", decoded.get_algorithm());
22 | ASSERT_EQ("JWT", decoded.get_type());
23 | auto aud = decoded.get_audience();
24 | ASSERT_EQ(1, aud.size());
25 | ASSERT_EQ("test", *aud.begin());
26 | }
27 |
28 | TEST(ClaimTest, SetAudienceAsString) {
29 | auto token = jwt::create().set_type("JWT").set_audience("test").sign(jwt::algorithm::hs256("test"));
30 | ASSERT_EQ("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ0ZXN0In0.ny5Fa0vzAg7tNL95KWg_ecBNd3XP3tdAzq0SFA6diY4",
31 | token);
32 | }
33 |
34 | TEST(ClaimTest, AudienceAsSet) {
35 | std::string const token = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJhdWQiOlsidGVzdCIsInRlc3QyIl19.";
36 | auto decoded = jwt::decode(token);
37 |
38 | ASSERT_TRUE(decoded.has_algorithm());
39 | ASSERT_TRUE(decoded.has_type());
40 | ASSERT_FALSE(decoded.has_content_type());
41 | ASSERT_FALSE(decoded.has_key_id());
42 | ASSERT_FALSE(decoded.has_issuer());
43 | ASSERT_FALSE(decoded.has_subject());
44 | ASSERT_TRUE(decoded.has_audience());
45 | ASSERT_FALSE(decoded.has_expires_at());
46 | ASSERT_FALSE(decoded.has_not_before());
47 | ASSERT_FALSE(decoded.has_issued_at());
48 | ASSERT_FALSE(decoded.has_id());
49 |
50 | ASSERT_EQ("none", decoded.get_algorithm());
51 | ASSERT_EQ("JWT", decoded.get_type());
52 | auto aud = decoded.get_audience();
53 | ASSERT_EQ(2, aud.size());
54 | ASSERT_TRUE(aud.count("test") > 0);
55 | ASSERT_TRUE(aud.count("test2") > 0);
56 | }
57 |
58 | TEST(ClaimTest, SetAudienceAsSet) {
59 | auto token = jwt::create()
60 | .set_type("JWT")
61 | .set_audience({{picojson::value("test"), picojson::value("test2")}})
62 | .sign(jwt::algorithm::none{});
63 | ASSERT_EQ("eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJhdWQiOlsidGVzdCIsInRlc3QyIl19.", token);
64 | }
65 |
66 | TEST(ClaimTest, SetArray) {
67 | std::vector vect = {100, 20, 10};
68 | auto token =
69 | jwt::create().set_payload_claim("test", jwt::claim(vect.begin(), vect.end())).sign(jwt::algorithm::none{});
70 | ASSERT_EQ(token, "eyJhbGciOiJub25lIn0.eyJ0ZXN0IjpbMTAwLDIwLDEwXX0.");
71 | }
72 |
73 | TEST(ClaimTest, SetObject) {
74 | std::istringstream iss{"{\"api-x\": [1]}"};
75 | jwt::claim object;
76 | iss >> object;
77 | ASSERT_EQ(object.get_type(), jwt::json::type::object);
78 |
79 | auto token = jwt::create().set_payload_claim("namespace", object).sign(jwt::algorithm::hs256("test"));
80 | ASSERT_EQ(token,
81 | "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lc3BhY2UiOnsiYXBpLXgiOlsxXX19.F8I6I2RcSF98bKa0IpIz09fRZtHr1CWnWKx2za-tFQA");
82 | }
83 |
84 | TEST(ClaimTest, SetAlgorithm) {
85 | auto token = jwt::create().set_algorithm("test").sign(jwt::algorithm::none{});
86 |
87 | auto decoded_token = jwt::decode(token);
88 | ASSERT_EQ(decoded_token.get_algorithm(), "test");
89 | }
90 |
91 | TEST(ClaimTest, AsInt) {
92 | jwt::claim c(picojson::value(static_cast(10)));
93 | ASSERT_EQ(c.as_integer(), 10);
94 | }
95 |
96 | TEST(ClaimTest, AsDate) {
97 | jwt::claim c(picojson::value(static_cast(10)));
98 | ASSERT_EQ(c.as_date(), std::chrono::system_clock::from_time_t(10));
99 | }
100 |
101 | TEST(ClaimTest, PicoJSONTraitsAccessorsThrow) {
102 | jwt::traits::kazuho_picojson::value_type val;
103 | ASSERT_THROW(jwt::traits::kazuho_picojson::as_array(val), std::bad_cast);
104 | ASSERT_THROW(jwt::traits::kazuho_picojson::as_boolean(val), std::bad_cast);
105 | ASSERT_THROW(jwt::traits::kazuho_picojson::as_integer(val), std::bad_cast);
106 | ASSERT_THROW(jwt::traits::kazuho_picojson::as_number(val), std::bad_cast);
107 | ASSERT_THROW(jwt::traits::kazuho_picojson::as_object(val), std::bad_cast);
108 | ASSERT_THROW(jwt::traits::kazuho_picojson::as_string(val), std::bad_cast);
109 | ASSERT_THROW(jwt::traits::kazuho_picojson::get_type(val), std::logic_error);
110 | }
111 |
112 | TEST(ClaimTest, PicoJSONTraitsAsBool) {
113 | jwt::traits::kazuho_picojson::value_type val(true);
114 | ASSERT_EQ(jwt::traits::kazuho_picojson::as_boolean(val), true);
115 | ASSERT_EQ(jwt::traits::kazuho_picojson::get_type(val), jwt::json::type::boolean);
116 | }
117 |
118 | TEST(ClaimTest, PicoJSONTraitsAsDouble) {
119 | jwt::traits::kazuho_picojson::value_type val(10.0);
120 | ASSERT_EQ(jwt::traits::kazuho_picojson::as_number(val), (int)10);
121 | ASSERT_EQ(jwt::traits::kazuho_picojson::get_type(val), jwt::json::type::number);
122 | }
123 |
124 | TEST(ClaimTest, MapOfClaim) {
125 | using map = jwt::details::map_of_claims;
126 | ASSERT_THROW(map::parse_claims(R"##(__ not json __)##"), jwt::error::invalid_json_exception);
127 | const map claims{
128 | map::parse_claims(R"##({ "array": [1], "string" : "hello world", "number": 9.9, "bool": true})##")};
129 |
130 | ASSERT_TRUE(claims.has_claim("array"));
131 | ASSERT_TRUE(claims.has_claim("string"));
132 | ASSERT_TRUE(claims.has_claim("number"));
133 | ASSERT_TRUE(claims.has_claim("bool"));
134 | ASSERT_FALSE(claims.has_claim("__missing__"));
135 |
136 | ASSERT_EQ(map::basic_claim_t{claims.get_claim("array").as_array().at(0)}.as_integer(), (int)1);
137 | ASSERT_EQ(claims.get_claim("string").as_string(), "hello world");
138 | ASSERT_EQ(claims.get_claim("number").as_number(), 9.9);
139 | ASSERT_EQ(claims.get_claim("bool").as_boolean(), true);
140 | ASSERT_THROW(claims.get_claim("__missing__"), jwt::error::claim_not_present_exception);
141 | }
142 |
--------------------------------------------------------------------------------
/tests/TestMain.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | int main(int argc, char* argv[]) {
4 | ::testing::InitGoogleTest(&argc, argv);
5 | return RUN_ALL_TESTS();
6 | }
7 |
--------------------------------------------------------------------------------
/tests/TokenFormatTest.cpp:
--------------------------------------------------------------------------------
1 | #include "jwt-cpp/jwt.h"
2 | #include
3 |
4 | TEST(TokenFormatTest, MissingDot) {
5 | ASSERT_THROW(jwt::decode("eyJhbGciOiJub25lIiwidHlwIjoiSldTIn0.eyJpc3MiOiJhdXRoMCJ9"), std::invalid_argument);
6 | ASSERT_THROW(jwt::decode("eyJhbGciOiJub25lIiwidHlwIjoiSldTIn0eyJpc3MiOiJhdXRoMCJ9."), std::invalid_argument);
7 | ASSERT_THROW(jwt::decode("eyJhbGciOiJub25lIiwidHlwIjoiSldTIn0eyJpc3MiOiJhdXRoMCJ9"), std::invalid_argument);
8 | }
9 |
10 | TEST(TokenFormatTest, InvalidChar) {
11 | ASSERT_THROW(jwt::decode("eyJhbGciOiJub25lIiwidHlwIjoiSldTIn0().eyJpc3MiOiJhdXRoMCJ9."), std::runtime_error);
12 | }
13 |
14 | TEST(TokenFormatTest, InvalidJSON) {
15 | ASSERT_THROW(jwt::decode("YXsiYWxnIjoibm9uZSIsInR5cCI6IkpXUyJ9YQ.eyJpc3MiOiJhdXRoMCJ9."), std::runtime_error);
16 | }
17 |
18 | #include "jwt-cpp/traits/nlohmann-json/traits.h"
19 |
20 | TEST(TokenFormatTest, GitHubIssue341) {
21 | std::string const token =
22 | "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJjYXV0aDAiLCJleHAiOjE3MTMzODgxNjgsInN1YiI6InRlc3RfdXNlciJ9."
23 | "dlAk0mSWk1Clzfi1PMq7Omxun3EyEqh-AAu-fTkpabA67ZKenawAQhZO8glY93flukpJCqHLVtukaes6ZSOjGw";
24 | auto decoded = jwt::decoded_jwt(token);
25 |
26 | ASSERT_TRUE(decoded.has_algorithm());
27 | ASSERT_TRUE(decoded.has_type());
28 | ASSERT_TRUE(decoded.has_issuer());
29 | ASSERT_TRUE(decoded.has_subject());
30 |
31 | ASSERT_EQ("ES256", decoded.get_algorithm());
32 | ASSERT_EQ("JWT", decoded.get_type());
33 | ASSERT_EQ("cauth0", decoded.get_issuer());
34 | ASSERT_EQ("test_user", decoded.get_subject());
35 | }
36 |
--------------------------------------------------------------------------------
/tests/cmake/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.8)
2 | project(jwt-cpp-installation-tests)
3 |
4 | set(TEST CACHE STRING "The test source file to be used")
5 |
6 | find_package(jwt-cpp 0.7.1 EXACT REQUIRED CONFIG)
7 |
8 | add_executable(test-project ${TEST}.cpp)
9 | target_link_libraries(test-project jwt-cpp::jwt-cpp)
10 |
--------------------------------------------------------------------------------
/tests/cmake/base64-is-disabled.cpp:
--------------------------------------------------------------------------------
1 | #ifndef JWT_DISABLE_BASE64
2 | #error "This test expects 'JWT_DISABLE_BASE64' to be defined!"
3 | #endif
4 |
5 | #include "jwt-cpp/jwt.h"
6 |
7 | int main() {
8 | jwt::date date;
9 | return 0;
10 | }
11 |
--------------------------------------------------------------------------------
/tests/cmake/defaults-enabled.cpp:
--------------------------------------------------------------------------------
1 | #include "jwt-cpp/jwt.h"
2 |
3 | int main() {
4 | jwt::claim claim;
5 | return 0;
6 | }
7 |
--------------------------------------------------------------------------------
/tests/cmake/libressl-is-used.cpp:
--------------------------------------------------------------------------------
1 | #if !__has_include()
2 | #error "missing LibreSSL's TLS header!"
3 | #endif
4 |
5 | #include
6 |
7 | #include "jwt-cpp/jwt.h"
8 |
9 | int main() {
10 | tls_init();
11 | jwt::date date;
12 | return 0;
13 | }
14 |
--------------------------------------------------------------------------------
/tests/cmake/picojson-is-disabled.cpp:
--------------------------------------------------------------------------------
1 | #ifndef JWT_DISABLE_PICOJSON
2 | #error "This test expects 'JWT_DISABLE_PICOJSON' to be defined!"
3 | #endif
4 |
5 | #include "jwt-cpp/jwt.h"
6 |
7 | int main() {
8 | jwt::date date;
9 | return 0;
10 | }
11 |
--------------------------------------------------------------------------------
/tests/cmake/wolfssl-is-used.cpp:
--------------------------------------------------------------------------------
1 | #if !__has_include()
2 | #error "missing wolfSSL's SSL header!"
3 | #endif
4 |
5 | // See https://github.com/Thalhammer/jwt-cpp/pull/352
6 | #ifndef EXTERNAL_OPTS_OPENVPN
7 | #error "missing wolfSSL's OPENSSL_EXTRA macro!"
8 | #endif
9 |
10 | #include "jwt-cpp/jwt.h"
11 |
12 | #include
13 |
14 | int main() {
15 | wolfSSL_library_init();
16 | jwt::date date;
17 | return 0;
18 | }
19 |
--------------------------------------------------------------------------------
/tests/fuzz/BaseDecodeFuzz.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | extern "C" {
4 |
5 | int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
6 | try {
7 | const auto bin = jwt::base::decode(std::string{(char*)Data, Size});
8 | } catch (const std::runtime_error&) {
9 | // parse errors are ok, because input may be random bytes
10 | }
11 | return 0; // Non-zero return values are reserved for future use.
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/tests/fuzz/BaseEncodeFuzz.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | extern "C" {
4 |
5 | int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
6 | jwt::base::encode(std::string{(char*)Data, Size});
7 | return 0; // Non-zero return values are reserved for future use.
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/tests/fuzz/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | if(NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL Clang)
2 | message(FATAL_ERROR "Fuzzing is only available on Clang")
3 | endif()
4 |
5 | function(ADD_FUZZING_EXECUTABLE TARGET)
6 | add_executable(jwt-cpp-fuzz-${TARGET} "${TARGET}.cpp")
7 | target_compile_options(
8 | jwt-cpp-fuzz-${TARGET} PRIVATE -g -O1 -fsanitize=fuzzer,address,signed-integer-overflow,undefined
9 | -fno-omit-frame-pointer)
10 | target_link_options(jwt-cpp-fuzz-${TARGET} PRIVATE -fsanitize=fuzzer,address,signed-integer-overflow,undefined
11 | -fno-omit-frame-pointer)
12 | target_link_libraries(jwt-cpp-fuzz-${TARGET} PRIVATE jwt-cpp::jwt-cpp)
13 | endfunction()
14 |
15 | add_fuzzing_executable(BaseEncodeFuzz)
16 | add_custom_target(jwt-cpp-fuzz-BaseEncodeFuzz-run COMMAND jwt-cpp-fuzz-BaseEncodeFuzz -runs=100000)
17 |
18 | add_fuzzing_executable(BaseDecodeFuzz)
19 | add_custom_target(jwt-cpp-fuzz-BaseDecodeFuzz-run COMMAND jwt-cpp-fuzz-BaseDecodeFuzz -runs=100000 decode-corpus
20 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
21 |
22 | add_fuzzing_executable(TokenDecodeFuzz)
23 | add_custom_target(jwt-cpp-fuzz-TokenDecodeFuzz-run COMMAND jwt-cpp-fuzz-TokenDecodeFuzz -runs=100000 token-corpus
24 | WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})
25 |
--------------------------------------------------------------------------------
/tests/fuzz/TokenDecodeFuzz.cpp:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | extern "C" {
4 |
5 | int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
6 | try {
7 | // step 1: parse input
8 | const auto jwt1 = jwt::decode(std::string{(char*)Data, Size});
9 |
10 | try {
11 | // step 2: round trip
12 | std::string s1 = jwt1.get_token();
13 | const auto jwt2 = jwt::decode(s1);
14 |
15 | // tokens must match
16 | if (s1 != jwt2.get_token()) abort();
17 | } catch (...) {
18 | // parsing raw data twice must not fail
19 | abort();
20 | }
21 | } catch (...) {
22 | // parse errors are ok, because input may be random bytes
23 | }
24 |
25 | return 0; // Non-zero return values are reserved for future use.
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/tests/fuzz/decode-corpus/086a3aa337038cac8a75a05131444f222e48aee8:
--------------------------------------------------------------------------------
1 | FMF=
--------------------------------------------------------------------------------
/tests/fuzz/decode-corpus/8ebaef2304e91465585c8d7fcf4d9f939e08d6b4:
--------------------------------------------------------------------------------
1 | eCy
--------------------------------------------------------------------------------
/tests/fuzz/decode-corpus/ba528234d9f6949ed9c9626c08a782f6e7c15b8b:
--------------------------------------------------------------------------------
1 | FF==
--------------------------------------------------------------------------------
/tests/fuzz/decode-corpus/de1028a3fe87471f027522c3ed9ec02b8364a006:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Thalhammer/jwt-cpp/0c676f86b7ec78fed88cbd1de259e1ed994779c9/tests/fuzz/decode-corpus/de1028a3fe87471f027522c3ed9ec02b8364a006
--------------------------------------------------------------------------------
/tests/fuzz/decode-corpus/e8f531caaa67cecb1c7b162f3e1d4e320d79befd:
--------------------------------------------------------------------------------
1 | eCyI
--------------------------------------------------------------------------------
/tests/fuzz/token-corpus/9d891e731f75deae56884d79e9816736b7488080:
--------------------------------------------------------------------------------
1 | ..
--------------------------------------------------------------------------------
/tests/fuzz/token-corpus/ff384e2421a333cd52f259cec14c7f790d595db9:
--------------------------------------------------------------------------------
1 | eyJhbGci..
--------------------------------------------------------------------------------
/tests/fuzz/token-corpus/valid-sample:
--------------------------------------------------------------------------------
1 | eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE
--------------------------------------------------------------------------------
/tests/traits/BoostJsonTest.cpp:
--------------------------------------------------------------------------------
1 | #include "jwt-cpp/traits/boost-json/traits.h"
2 |
3 | #include
4 |
5 | TEST(BoostJsonTest, BasicClaims) {
6 | const auto string = jwt::basic_claim(jwt::traits::boost_json::string_type("string"));
7 | ASSERT_EQ(string.get_type(), jwt::json::type::string);
8 |
9 | const auto array =
10 | jwt::basic_claim(std::set{"string", "string"});
11 | ASSERT_EQ(array.get_type(), jwt::json::type::array);
12 |
13 | jwt::traits::boost_json::value_type jvi = 159816816;
14 | const auto integer = jwt::basic_claim(jvi);
15 | ASSERT_EQ(integer.get_type(), jwt::json::type::integer);
16 | }
17 |
18 | TEST(BoostJsonTest, AudienceAsString) {
19 | jwt::traits::boost_json::string_type token =
20 | "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ0ZXN0In0.WZnM3SIiSRHsbO3O7Z2bmIzTJ4EC32HRBKfLznHhrh4";
21 | auto decoded = jwt::decode(token);
22 |
23 | ASSERT_TRUE(decoded.has_algorithm());
24 | ASSERT_TRUE(decoded.has_type());
25 | ASSERT_FALSE(decoded.has_content_type());
26 | ASSERT_FALSE(decoded.has_key_id());
27 | ASSERT_FALSE(decoded.has_issuer());
28 | ASSERT_FALSE(decoded.has_subject());
29 | ASSERT_TRUE(decoded.has_audience());
30 | ASSERT_FALSE(decoded.has_expires_at());
31 | ASSERT_FALSE(decoded.has_not_before());
32 | ASSERT_FALSE(decoded.has_issued_at());
33 | ASSERT_FALSE(decoded.has_id());
34 |
35 | ASSERT_EQ("HS256", decoded.get_algorithm());
36 | ASSERT_EQ("JWT", decoded.get_type());
37 | auto aud = decoded.get_audience();
38 | ASSERT_EQ(1, aud.size());
39 | ASSERT_EQ("test", *aud.begin());
40 | }
41 |
42 | TEST(BoostJsonTest, SetArray) {
43 | std::vector vect = {100, 20, 10};
44 | auto token = jwt::create()
45 | .set_payload_claim("test", jwt::basic_claim