Annotate

mod_http_oauth2/mod_http_oauth2.lua @ 6323:4f9b42c53d0f

mod_http_oauth2: Check grant type before issuing refresh token This prevents even issuing a refresh token to a client that has not registered the corresponding grant type. The grant type dispatcher also checks before invoking the refresh token grant type handler.
author Kim Alvefur <zash@zash.se>
date Thu, 03 Jul 2025 15:34:42 +0200
parent 6322:dfc035ecabb4
child 6324:5dc4ec836ce2
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
5501
57ce8c4017e7 mod_http_oauth2: Sort imports
Kim Alvefur <zash@zash.se>
parents: 5495
diff changeset
1 local usermanager = require "core.usermanager";
57ce8c4017e7 mod_http_oauth2: Sort imports
Kim Alvefur <zash@zash.se>
parents: 5495
diff changeset
2 local url = require "socket.url";
57ce8c4017e7 mod_http_oauth2: Sort imports
Kim Alvefur <zash@zash.se>
parents: 5495
diff changeset
3 local array = require "util.array";
4271
9623b99bb8d2 mod_http_oauth2: Keep authorization codes in memory instead of storage
Kim Alvefur <zash@zash.se>
parents: 4270
diff changeset
4 local cache = require "util.cache";
5501
57ce8c4017e7 mod_http_oauth2: Sort imports
Kim Alvefur <zash@zash.se>
parents: 5495
diff changeset
5 local encodings = require "util.encodings";
57ce8c4017e7 mod_http_oauth2: Sort imports
Kim Alvefur <zash@zash.se>
parents: 5495
diff changeset
6 local errors = require "util.error";
57ce8c4017e7 mod_http_oauth2: Sort imports
Kim Alvefur <zash@zash.se>
parents: 5495
diff changeset
7 local hashes = require "util.hashes";
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
8 local http = require "util.http";
5501
57ce8c4017e7 mod_http_oauth2: Sort imports
Kim Alvefur <zash@zash.se>
parents: 5495
diff changeset
9 local id = require "util.id";
57ce8c4017e7 mod_http_oauth2: Sort imports
Kim Alvefur <zash@zash.se>
parents: 5495
diff changeset
10 local it = require "util.iterators";
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
11 local jid = require "util.jid";
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
12 local json = require "util.json";
5501
57ce8c4017e7 mod_http_oauth2: Sort imports
Kim Alvefur <zash@zash.se>
parents: 5495
diff changeset
13 local schema = require "util.jsonschema";
57ce8c4017e7 mod_http_oauth2: Sort imports
Kim Alvefur <zash@zash.se>
parents: 5495
diff changeset
14 local jwt = require "util.jwt";
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
15 local random = require "util.random";
5209
942f8a2f722d mod_http_oauth2: Allow non-HTTPS on localhost URLs
Matthew Wild <mwild1@gmail.com>
parents: 5208
diff changeset
16 local set = require "util.set";
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
17 local st = require "util.stanza";
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
18
5501
57ce8c4017e7 mod_http_oauth2: Sort imports
Kim Alvefur <zash@zash.se>
parents: 5495
diff changeset
19 local base64 = encodings.base64;
57ce8c4017e7 mod_http_oauth2: Sort imports
Kim Alvefur <zash@zash.se>
parents: 5495
diff changeset
20
5383
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
21 local function b64url(s)
5392
c0a6f39caf47 mod_http_oauth2: Fix missing base64 part of base64url (Thanks KeyCloak)
Kim Alvefur <zash@zash.se>
parents: 5391
diff changeset
22 return (base64.encode(s):gsub("[+/=]", { ["+"] = "-", ["/"] = "_", ["="] = "" }))
5383
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
23 end
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
24
5400
71766a4a7322 mod_http_oauth2: Reduce line count of metadata construction
Kim Alvefur <zash@zash.se>
parents: 5399
diff changeset
25 local function tmap(t)
71766a4a7322 mod_http_oauth2: Reduce line count of metadata construction
Kim Alvefur <zash@zash.se>
parents: 5399
diff changeset
26 return function(k)
71766a4a7322 mod_http_oauth2: Reduce line count of metadata construction
Kim Alvefur <zash@zash.se>
parents: 5399
diff changeset
27 return t[k];
71766a4a7322 mod_http_oauth2: Reduce line count of metadata construction
Kim Alvefur <zash@zash.se>
parents: 5399
diff changeset
28 end
71766a4a7322 mod_http_oauth2: Reduce line count of metadata construction
Kim Alvefur <zash@zash.se>
parents: 5399
diff changeset
29 end
71766a4a7322 mod_http_oauth2: Reduce line count of metadata construction
Kim Alvefur <zash@zash.se>
parents: 5399
diff changeset
30
6317
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
31 local function array_contains(haystack, needle)
6321
e174e12549e1 mod_http_oauth2: Handle absent array argument in array member check
Kim Alvefur <zash@zash.se>
parents: 6320
diff changeset
32 if not haystack then
e174e12549e1 mod_http_oauth2: Handle absent array argument in array member check
Kim Alvefur <zash@zash.se>
parents: 6320
diff changeset
33 return false
e174e12549e1 mod_http_oauth2: Handle absent array argument in array member check
Kim Alvefur <zash@zash.se>
parents: 6320
diff changeset
34 end
6320
ebcf612da2b1 mod_http_oauth2: Use numeric for loop instead of ipairs
Kim Alvefur <zash@zash.se>
parents: 6319
diff changeset
35 for i = 1, #haystack do
ebcf612da2b1 mod_http_oauth2: Use numeric for loop instead of ipairs
Kim Alvefur <zash@zash.se>
parents: 6319
diff changeset
36 if haystack[i] == needle then
6317
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
37 return true
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
38 end
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
39 end
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
40 return false
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
41 end
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
42
5984
97375a78d2b5 mod_http_oauth2: Reject URLs with 'userinfo' part (thanks mimi89999)
Kim Alvefur <zash@zash.se>
parents: 5963
diff changeset
43 local function strict_url_parse(urlstr)
97375a78d2b5 mod_http_oauth2: Reject URLs with 'userinfo' part (thanks mimi89999)
Kim Alvefur <zash@zash.se>
parents: 5963
diff changeset
44 local url_parts = url.parse(urlstr);
97375a78d2b5 mod_http_oauth2: Reject URLs with 'userinfo' part (thanks mimi89999)
Kim Alvefur <zash@zash.se>
parents: 5963
diff changeset
45 if not url_parts then return url_parts; end
97375a78d2b5 mod_http_oauth2: Reject URLs with 'userinfo' part (thanks mimi89999)
Kim Alvefur <zash@zash.se>
parents: 5963
diff changeset
46 if url_parts.userinfo then return false; end
5985
e8bf46a7bb27 mod_http_oauth2: Ensure URL ports are integer in correct range
Kim Alvefur <zash@zash.se>
parents: 5984
diff changeset
47 if url_parts.port then
e8bf46a7bb27 mod_http_oauth2: Ensure URL ports are integer in correct range
Kim Alvefur <zash@zash.se>
parents: 5984
diff changeset
48 local port = tonumber(url_parts.port);
e8bf46a7bb27 mod_http_oauth2: Ensure URL ports are integer in correct range
Kim Alvefur <zash@zash.se>
parents: 5984
diff changeset
49 if not port then return false; end
5988
538f468f9a65 mod_http_oauth2: Simplify negation in condition
Kim Alvefur <zash@zash.se>
parents: 5986
diff changeset
50 if port <= 0 or port > 0xffff then return false; end
5985
e8bf46a7bb27 mod_http_oauth2: Ensure URL ports are integer in correct range
Kim Alvefur <zash@zash.se>
parents: 5984
diff changeset
51 if port ~= math.floor(port) then return false; end
e8bf46a7bb27 mod_http_oauth2: Ensure URL ports are integer in correct range
Kim Alvefur <zash@zash.se>
parents: 5984
diff changeset
52 end
5986
5f8a306c8306 mod_http_oauth2: Require a stringprepped host part of URLs
Kim Alvefur <zash@zash.se>
parents: 5985
diff changeset
53 if url_parts.host then
5f8a306c8306 mod_http_oauth2: Require a stringprepped host part of URLs
Kim Alvefur <zash@zash.se>
parents: 5985
diff changeset
54 if encodings.stringprep.nameprep(url_parts.host) ~= url_parts.host then
5f8a306c8306 mod_http_oauth2: Require a stringprepped host part of URLs
Kim Alvefur <zash@zash.se>
parents: 5985
diff changeset
55 return false;
5f8a306c8306 mod_http_oauth2: Require a stringprepped host part of URLs
Kim Alvefur <zash@zash.se>
parents: 5985
diff changeset
56 end
5989
7308ec4aaad1 mod_http_oauth2: Fix error due to mistake in 5f8a306c8306
Kim Alvefur <zash@zash.se>
parents: 5988
diff changeset
57 if not encodings.idna.to_ascii(url_parts.host) then
5986
5f8a306c8306 mod_http_oauth2: Require a stringprepped host part of URLs
Kim Alvefur <zash@zash.se>
parents: 5985
diff changeset
58 return false;
5f8a306c8306 mod_http_oauth2: Require a stringprepped host part of URLs
Kim Alvefur <zash@zash.se>
parents: 5985
diff changeset
59 end
5f8a306c8306 mod_http_oauth2: Require a stringprepped host part of URLs
Kim Alvefur <zash@zash.se>
parents: 5985
diff changeset
60 end
5984
97375a78d2b5 mod_http_oauth2: Reject URLs with 'userinfo' part (thanks mimi89999)
Kim Alvefur <zash@zash.se>
parents: 5963
diff changeset
61 return url_parts;
97375a78d2b5 mod_http_oauth2: Reject URLs with 'userinfo' part (thanks mimi89999)
Kim Alvefur <zash@zash.se>
parents: 5963
diff changeset
62 end
97375a78d2b5 mod_http_oauth2: Reject URLs with 'userinfo' part (thanks mimi89999)
Kim Alvefur <zash@zash.se>
parents: 5963
diff changeset
63
5513
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
64 local function strict_formdecode(query)
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
65 if not query then
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
66 return nil;
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
67 end
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
68 local params = http.formdecode(query);
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
69 if type(params) ~= "table" then
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
70 return nil, "no-pairs";
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
71 end
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
72 local dups = {};
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
73 for _, pair in ipairs(params) do
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
74 if dups[pair.name] then
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
75 return nil, "duplicate";
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
76 end
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
77 dups[pair.name] = true;
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
78 end
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
79 return params;
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
80 end
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
81
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
82 local function read_file(base_path, fn, required)
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
83 local f, err = io.open(base_path .. "/" .. fn);
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
84 if not f then
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
85 module:log(required and "error" or "debug", "Unable to load template file: %s", err);
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
86 if required then
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
87 return error("Failed to load templates");
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
88 end
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
89 return nil;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
90 end
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
91 local data = assert(f:read("*a"));
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
92 assert(f:close());
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
93 return data;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
94 end
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
95
5554
90449babaa48 mod_http_oauth2: Make allowed locales configurable
Kim Alvefur <zash@zash.se>
parents: 5553
diff changeset
96 local allowed_locales = module:get_option_array("allowed_oauth2_locales", {});
90449babaa48 mod_http_oauth2: Make allowed locales configurable
Kim Alvefur <zash@zash.se>
parents: 5553
diff changeset
97 -- TODO Allow translations or per-locale templates somehow.
90449babaa48 mod_http_oauth2: Make allowed locales configurable
Kim Alvefur <zash@zash.se>
parents: 5553
diff changeset
98
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
99 local template_path = module:get_option_path("oauth2_template_path", "html");
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
100 local templates = {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
101 login = read_file(template_path, "login.html", true);
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
102 consent = read_file(template_path, "consent.html", true);
5495
7998b49d6512 mod_http_oauth2: Create proper template for OOB code delivery
Kim Alvefur <zash@zash.se>
parents: 5480
diff changeset
103 oob = read_file(template_path, "oob.html", true);
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
104 device = read_file(template_path, "device.html", true);
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
105 error = read_file(template_path, "error.html", true);
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
106 css = read_file(template_path, "style.css");
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
107 js = read_file(template_path, "script.js");
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
108 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
109
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
110 local site_name = module:get_option_string("site_name", module.host);
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
111
5547
d4a2997deae9 mod_http_oauth2: Make CSP configurable
Kim Alvefur <zash@zash.se>
parents: 5544
diff changeset
112 local security_policy = module:get_option_string("oauth2_security_policy", "default-src 'self'");
d4a2997deae9 mod_http_oauth2: Make CSP configurable
Kim Alvefur <zash@zash.se>
parents: 5544
diff changeset
113
5544
cb141088eff0 mod_http_oauth2: Remove underscore prefix
Kim Alvefur <zash@zash.se>
parents: 5526
diff changeset
114 local render_html = require"util.interpolation".new("%b{}", st.xml_escape);
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
115 local function render_page(template, data, sensitive)
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
116 data = data or {};
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
117 data.site_name = site_name;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
118 local resp = {
5470
40c990159006 mod_http_oauth2: Use error status code when rendering error page
Kim Alvefur <zash@zash.se>
parents: 5469
diff changeset
119 status_code = data.error and data.error.code or 200;
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
120 headers = {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
121 ["Content-Type"] = "text/html; charset=utf-8";
5547
d4a2997deae9 mod_http_oauth2: Make CSP configurable
Kim Alvefur <zash@zash.se>
parents: 5544
diff changeset
122 ["Content-Security-Policy"] = security_policy;
5479
30e2722c9fa3 mod_http_oauth2: Disable Referrer via header
Kim Alvefur <zash@zash.se>
parents: 5478
diff changeset
123 ["Referrer-Policy"] = "no-referrer";
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
124 ["X-Frame-Options"] = "DENY";
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
125 ["Cache-Control"] = (sensitive and "no-store" or "no-cache")..", private";
5509
ae007be8a6bd mod_http_oauth2: Add Cache-Control and Pragma headers per by RFC 6749
Kim Alvefur <zash@zash.se>
parents: 5502
diff changeset
126 ["Pragma"] = "no-cache";
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
127 };
5544
cb141088eff0 mod_http_oauth2: Remove underscore prefix
Kim Alvefur <zash@zash.se>
parents: 5526
diff changeset
128 body = render_html(template, data);
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
129 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
130 return resp;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
131 end
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
132
5502
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
133 local authorization_server_metadata = nil;
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
134
3915
80dffbbd056b mod_rest, mod_http_oauth2: Switch from mod_authtokens to mod_tokenauth per Prosody bf81523e2ff4
Matthew Wild <mwild1@gmail.com>
parents: 3908
diff changeset
135 local tokens = module:depends("tokenauth");
3908
8ac5d9933106 mod_http_oauth2: Implement real tokens using mod_authtokens
Matthew Wild <mwild1@gmail.com>
parents: 3903
diff changeset
136
5624
d8622797e315 mod_http_oauth2: Shorten default token validity periods
Kim Alvefur <zash@zash.se>
parents: 5623
diff changeset
137 local default_access_ttl = module:get_option_number("oauth2_access_token_ttl", 3600);
5626
81042c2a235a mod_http_oauth2: Don't use new time period API just yet
Kim Alvefur <zash@zash.se>
parents: 5625
diff changeset
138 local default_refresh_ttl = module:get_option_number("oauth2_refresh_token_ttl", 604800);
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
139
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
140 -- Used to derive client_secret from client_id, set to enable stateless dynamic registration.
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
141 local registration_key = module:get_option_string("oauth2_registration_key");
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
142 local registration_algo = module:get_option_string("oauth2_registration_algorithm", "HS256");
5416
2393dbae51ed mod_http_oauth2: Add option for specifying TTL of registered clients
Kim Alvefur <zash@zash.se>
parents: 5409
diff changeset
143 local registration_ttl = module:get_option("oauth2_registration_ttl", nil);
2393dbae51ed mod_http_oauth2: Add option for specifying TTL of registered clients
Kim Alvefur <zash@zash.se>
parents: 5409
diff changeset
144 local registration_options = module:get_option("oauth2_registration_options",
2393dbae51ed mod_http_oauth2: Add option for specifying TTL of registered clients
Kim Alvefur <zash@zash.se>
parents: 5409
diff changeset
145 { default_ttl = registration_ttl; accept_expired = not registration_ttl });
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
146
5739
426c42c11f89 mod_http_oauth2: Make defaults more secure
Kim Alvefur <zash@zash.se>
parents: 5738
diff changeset
147 local pkce_required = module:get_option_boolean("oauth2_require_code_challenge", true);
426c42c11f89 mod_http_oauth2: Make defaults more secure
Kim Alvefur <zash@zash.se>
parents: 5738
diff changeset
148 local respect_prompt = module:get_option_boolean("oauth2_respect_oidc_prompt", false);
6240
ab14e7ecb82f mod_http_oauth2: Allow JIDs as username for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6239
diff changeset
149 local expect_username_jid = module:get_option_boolean("oauth2_expect_username_jid", false);
5383
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
150
5199
f48628dc83f1 mod_http_oauth2: Separate client_secret verification key from JWT key
Kim Alvefur <zash@zash.se>
parents: 5198
diff changeset
151 local verification_key;
5459
260a859be86a mod_http_oauth2: Rename variables to improve clarity
Kim Alvefur <zash@zash.se>
parents: 5458
diff changeset
152 local sign_client, verify_client;
5196
6b63af56c8ac mod_http_oauth2: Remove error message
Kim Alvefur <zash@zash.se>
parents: 5195
diff changeset
153 if registration_key then
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
154 -- Tie it to the host if global
5199
f48628dc83f1 mod_http_oauth2: Separate client_secret verification key from JWT key
Kim Alvefur <zash@zash.se>
parents: 5198
diff changeset
155 verification_key = hashes.hmac_sha256(registration_key, module.host);
5459
260a859be86a mod_http_oauth2: Rename variables to improve clarity
Kim Alvefur <zash@zash.se>
parents: 5458
diff changeset
156 sign_client, verify_client = jwt.init(registration_algo, registration_key, registration_key, registration_options);
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
157 end
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
158
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
159 local new_device_token, verify_device_token = jwt.init("HS256", random.bytes(32), nil, { default_ttl = 600 });
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
160
5510
a49d73e4262e mod_http_oauth2: Add client verification wrapper function
Kim Alvefur <zash@zash.se>
parents: 5509
diff changeset
161 -- verify and prepare client structure
a49d73e4262e mod_http_oauth2: Add client verification wrapper function
Kim Alvefur <zash@zash.se>
parents: 5509
diff changeset
162 local function check_client(client_id)
a49d73e4262e mod_http_oauth2: Add client verification wrapper function
Kim Alvefur <zash@zash.se>
parents: 5509
diff changeset
163 if not verify_client then
a49d73e4262e mod_http_oauth2: Add client verification wrapper function
Kim Alvefur <zash@zash.se>
parents: 5509
diff changeset
164 return nil, "client-registration-not-enabled";
a49d73e4262e mod_http_oauth2: Add client verification wrapper function
Kim Alvefur <zash@zash.se>
parents: 5509
diff changeset
165 end
a49d73e4262e mod_http_oauth2: Add client verification wrapper function
Kim Alvefur <zash@zash.se>
parents: 5509
diff changeset
166
a49d73e4262e mod_http_oauth2: Add client verification wrapper function
Kim Alvefur <zash@zash.se>
parents: 5509
diff changeset
167 local ok, client = verify_client(client_id);
5511
0860497152af mod_http_oauth2: Record hash of client_id to allow future verification
Kim Alvefur <zash@zash.se>
parents: 5510
diff changeset
168 if not ok then
0860497152af mod_http_oauth2: Record hash of client_id to allow future verification
Kim Alvefur <zash@zash.se>
parents: 5510
diff changeset
169 return ok, client;
0860497152af mod_http_oauth2: Record hash of client_id to allow future verification
Kim Alvefur <zash@zash.se>
parents: 5510
diff changeset
170 end
0860497152af mod_http_oauth2: Record hash of client_id to allow future verification
Kim Alvefur <zash@zash.se>
parents: 5510
diff changeset
171
0860497152af mod_http_oauth2: Record hash of client_id to allow future verification
Kim Alvefur <zash@zash.se>
parents: 5510
diff changeset
172 client.client_hash = b64url(hashes.sha256(client_id));
5510
a49d73e4262e mod_http_oauth2: Add client verification wrapper function
Kim Alvefur <zash@zash.se>
parents: 5509
diff changeset
173 return client;
a49d73e4262e mod_http_oauth2: Add client verification wrapper function
Kim Alvefur <zash@zash.se>
parents: 5509
diff changeset
174 end
a49d73e4262e mod_http_oauth2: Add client verification wrapper function
Kim Alvefur <zash@zash.se>
parents: 5509
diff changeset
175
5703
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
176 local purpose_map = { ["oauth2-refresh"] = "refresh_token"; ["oauth"] = "access_token" };
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
177
5449
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
178 -- scope : string | array | set
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
179 --
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
180 -- at each step, allow the same or a subset of scopes
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
181 -- (all ( client ( grant ( token ) ) ))
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
182 -- preserve order since it determines role if more than one granted
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
183
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
184 -- string -> array
5254
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
185 local function parse_scopes(scope_string)
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
186 return array(scope_string:gmatch("%S+"));
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
187 end
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
188
5502
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
189 local openid_claims = set.new();
6317
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
190
5502
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
191 module:add_item("openid-claim", "openid");
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
192
6317
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
193 -- https://openid.net/specs/openid-connect-core-1_0.html#OfflineAccess
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
194 -- The "offline_access" scope grants access to refresh tokens
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
195 module:add_item("openid-claim", "offline_access");
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
196
5502
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
197 module:handle_items("openid-claim", function(event)
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
198 authorization_server_metadata = nil;
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
199 openid_claims:add(event.item);
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
200 end, function()
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
201 authorization_server_metadata = nil;
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
202 openid_claims = set.new(module:get_host_items("openid-claim"));
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
203 end, true);
5337
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
204
5449
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
205 -- array -> array, array, array
5417
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
206 local function split_scopes(scope_list)
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
207 local claims, roles, unknown = array(), array(), array();
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
208 local all_roles = usermanager.get_all_roles(module.host);
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
209 for _, scope in ipairs(scope_list) do
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
210 if openid_claims:contains(scope) then
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
211 claims:push(scope);
5467
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
212 elseif scope == "xmpp" or all_roles[scope] then
5417
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
213 roles:push(scope);
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
214 else
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
215 unknown:push(scope);
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
216 end
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
217 end
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
218 return claims, roles, unknown;
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
219 end
5254
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
220
5417
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
221 local function can_assume_role(username, requested_role)
5467
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
222 return requested_role == "xmpp" or usermanager.user_can_assume_role(username, module.host, requested_role);
5417
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
223 end
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
224
5449
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
225 -- function (string) : function(string) : boolean
5427
d69c10327d6d mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents: 5426
diff changeset
226 local function role_assumable_by(username)
d69c10327d6d mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents: 5426
diff changeset
227 return function(role)
d69c10327d6d mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents: 5426
diff changeset
228 return can_assume_role(username, role);
d69c10327d6d mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents: 5426
diff changeset
229 end
d69c10327d6d mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents: 5426
diff changeset
230 end
d69c10327d6d mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents: 5426
diff changeset
231
5449
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
232 -- string, array --> array
5426
f75d95f27da7 mod_http_oauth2: Add function for filtering roles
Kim Alvefur <zash@zash.se>
parents: 5425
diff changeset
233 local function user_assumable_roles(username, requested_roles)
5427
d69c10327d6d mod_http_oauth2: More functional functions
Kim Alvefur <zash@zash.se>
parents: 5426
diff changeset
234 return array.filter(requested_roles, role_assumable_by(username));
5426
f75d95f27da7 mod_http_oauth2: Add function for filtering roles
Kim Alvefur <zash@zash.se>
parents: 5425
diff changeset
235 end
f75d95f27da7 mod_http_oauth2: Add function for filtering roles
Kim Alvefur <zash@zash.se>
parents: 5425
diff changeset
236
5449
9c19a6b8e542 mod_http_oauth2: Describe type signatures of scope handling functions
Kim Alvefur <zash@zash.se>
parents: 5448
diff changeset
237 -- string, string|nil --> string, string
5417
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
238 local function filter_scopes(username, requested_scope_string)
5428
07e166b34c4c mod_http_oauth2: Simplify code with the power of first class functions
Kim Alvefur <zash@zash.se>
parents: 5427
diff changeset
239 local requested_scopes, requested_roles = split_scopes(parse_scopes(requested_scope_string or ""));
5417
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
240
5428
07e166b34c4c mod_http_oauth2: Simplify code with the power of first class functions
Kim Alvefur <zash@zash.se>
parents: 5427
diff changeset
241 local granted_roles = user_assumable_roles(username, requested_roles);
07e166b34c4c mod_http_oauth2: Simplify code with the power of first class functions
Kim Alvefur <zash@zash.se>
parents: 5427
diff changeset
242 local granted_scopes = requested_scopes + granted_roles;
5417
3902082c42c4 mod_http_oauth2: Refactor scope handling into smaller functions
Kim Alvefur <zash@zash.se>
parents: 5416
diff changeset
243
5428
07e166b34c4c mod_http_oauth2: Simplify code with the power of first class functions
Kim Alvefur <zash@zash.se>
parents: 5427
diff changeset
244 local selected_role = granted_roles[1];
5254
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
245
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
246 return granted_scopes:concat(" "), selected_role;
4340
7cd3b7ec59e9 mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents: 4276
diff changeset
247 end
7cd3b7ec59e9 mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents: 4276
diff changeset
248
5213
dc0f502c12f1 mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents: 5210
diff changeset
249 local function code_expires_in(code) --> number, seconds until code expires
dc0f502c12f1 mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents: 5210
diff changeset
250 return os.difftime(code.expires, os.time());
4669
d3434fd151b5 mod_http_oauth2: Optimize cleanup timer
Kim Alvefur <zash@zash.se>
parents: 4370
diff changeset
251 end
d3434fd151b5 mod_http_oauth2: Optimize cleanup timer
Kim Alvefur <zash@zash.se>
parents: 4370
diff changeset
252
5213
dc0f502c12f1 mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents: 5210
diff changeset
253 local function code_expired(code) --> boolean, true: has expired, false: still valid
dc0f502c12f1 mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents: 5210
diff changeset
254 return code_expires_in(code) < 0;
4269
143515d0b212 mod_http_oauth2: Factor out authorization code validity decision
Kim Alvefur <zash@zash.se>
parents: 4265
diff changeset
255 end
143515d0b212 mod_http_oauth2: Factor out authorization code validity decision
Kim Alvefur <zash@zash.se>
parents: 4265
diff changeset
256
5774
d563a6b0dfb7 mod_http_oauth2: Comment on authorization code storage
Kim Alvefur <zash@zash.se>
parents: 5739
diff changeset
257 -- LRU cache for short-term storage of authorization codes and device codes
4271
9623b99bb8d2 mod_http_oauth2: Keep authorization codes in memory instead of storage
Kim Alvefur <zash@zash.se>
parents: 4270
diff changeset
258 local codes = cache.new(10000, function (_, code)
5774
d563a6b0dfb7 mod_http_oauth2: Comment on authorization code storage
Kim Alvefur <zash@zash.se>
parents: 5739
diff changeset
259 -- If the cache is full and the oldest item hasn't expired yet then we
d563a6b0dfb7 mod_http_oauth2: Comment on authorization code storage
Kim Alvefur <zash@zash.se>
parents: 5739
diff changeset
260 -- might be under some kind of DoS attack, so might as well reject further
d563a6b0dfb7 mod_http_oauth2: Comment on authorization code storage
Kim Alvefur <zash@zash.se>
parents: 5739
diff changeset
261 -- entries for a bit.
4271
9623b99bb8d2 mod_http_oauth2: Keep authorization codes in memory instead of storage
Kim Alvefur <zash@zash.se>
parents: 4270
diff changeset
262 return code_expired(code)
9623b99bb8d2 mod_http_oauth2: Keep authorization codes in memory instead of storage
Kim Alvefur <zash@zash.se>
parents: 4270
diff changeset
263 end);
9623b99bb8d2 mod_http_oauth2: Keep authorization codes in memory instead of storage
Kim Alvefur <zash@zash.se>
parents: 4270
diff changeset
264
5625
869c01d91aea mod_http_oauth2: Clean cache less frequently
Kim Alvefur <zash@zash.se>
parents: 5624
diff changeset
265 -- Clear out unredeemed codes so they don't linger in memory.
869c01d91aea mod_http_oauth2: Clean cache less frequently
Kim Alvefur <zash@zash.se>
parents: 5624
diff changeset
266 module:daily("Clear expired authorization codes", function()
5774
d563a6b0dfb7 mod_http_oauth2: Comment on authorization code storage
Kim Alvefur <zash@zash.se>
parents: 5739
diff changeset
267 -- The tail should be the least recently touched item, and most likely to
d563a6b0dfb7 mod_http_oauth2: Comment on authorization code storage
Kim Alvefur <zash@zash.se>
parents: 5739
diff changeset
268 -- have expired already, so check and remove that one until encountering
d563a6b0dfb7 mod_http_oauth2: Comment on authorization code storage
Kim Alvefur <zash@zash.se>
parents: 5739
diff changeset
269 -- one that has not expired.
4272
91b951fb3018 mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents: 4271
diff changeset
270 local k, code = codes:tail();
91b951fb3018 mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents: 4271
diff changeset
271 while code and code_expired(code) do
91b951fb3018 mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents: 4271
diff changeset
272 codes:set(k, nil);
91b951fb3018 mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents: 4271
diff changeset
273 k, code = codes:tail();
91b951fb3018 mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents: 4271
diff changeset
274 end
91b951fb3018 mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents: 4271
diff changeset
275 end)
91b951fb3018 mod_http_oauth2: Periodically trim unused authorization codes
Kim Alvefur <zash@zash.se>
parents: 4271
diff changeset
276
5207
c72e3b0914e8 mod_http_oauth: Factor out issuer URL calculation to a helper function
Matthew Wild <mwild1@gmail.com>
parents: 5206
diff changeset
277 local function get_issuer()
c72e3b0914e8 mod_http_oauth: Factor out issuer URL calculation to a helper function
Matthew Wild <mwild1@gmail.com>
parents: 5206
diff changeset
278 return (module:http_url(nil, "/"):gsub("/$", ""));
c72e3b0914e8 mod_http_oauth: Factor out issuer URL calculation to a helper function
Matthew Wild <mwild1@gmail.com>
parents: 5206
diff changeset
279 end
c72e3b0914e8 mod_http_oauth: Factor out issuer URL calculation to a helper function
Matthew Wild <mwild1@gmail.com>
parents: 5206
diff changeset
280
5458
813fe4f76286 mod_http_oauth2: Do minimal validation of private-use URI schemes
Kim Alvefur <zash@zash.se>
parents: 5457
diff changeset
281 -- Non-standard special redirect URI that has the AS show the authorization
813fe4f76286 mod_http_oauth2: Do minimal validation of private-use URI schemes
Kim Alvefur <zash@zash.se>
parents: 5457
diff changeset
282 -- code to the user for them to copy-paste into the client, which can then
813fe4f76286 mod_http_oauth2: Do minimal validation of private-use URI schemes
Kim Alvefur <zash@zash.se>
parents: 5457
diff changeset
283 -- continue as if it received it via redirect.
813fe4f76286 mod_http_oauth2: Do minimal validation of private-use URI schemes
Kim Alvefur <zash@zash.se>
parents: 5457
diff changeset
284 local oob_uri = "urn:ietf:wg:oauth:2.0:oob";
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
285 local device_uri = "urn:ietf:params:oauth:grant-type:device_code";
5458
813fe4f76286 mod_http_oauth2: Do minimal validation of private-use URI schemes
Kim Alvefur <zash@zash.se>
parents: 5457
diff changeset
286
5209
942f8a2f722d mod_http_oauth2: Allow non-HTTPS on localhost URLs
Matthew Wild <mwild1@gmail.com>
parents: 5208
diff changeset
287 local loopbacks = set.new({ "localhost", "127.0.0.1", "::1" });
942f8a2f722d mod_http_oauth2: Allow non-HTTPS on localhost URLs
Matthew Wild <mwild1@gmail.com>
parents: 5208
diff changeset
288
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
289 local function oauth_error(err_name, err_desc)
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
290 return errors.new({
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
291 type = "modify";
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
292 condition = "bad-request";
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
293 code = err_name == "invalid_client" and 401 or 400;
5821
fdf3056021dc mod_http_oauth2: Tweak fallback error text
Kim Alvefur <zash@zash.se>
parents: 5820
diff changeset
294 text = err_desc or err_name:gsub("^.", string.upper):gsub("_", " ");
4276
ec33b3b1136c mod_http_oauth2: Fix passing OAuth-specific error details
Kim Alvefur <zash@zash.se>
parents: 4272
diff changeset
295 extra = { oauth2_response = { error = err_name, error_description = err_desc } };
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
296 });
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
297 end
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
298
5248
b8b2bf0c1b4b mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents: 5247
diff changeset
299 -- client_id / client_metadata are pretty large, filter out a subset of
b8b2bf0c1b4b mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents: 5247
diff changeset
300 -- properties that are deemed useful e.g. in case tokens issued to a certain
b8b2bf0c1b4b mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents: 5247
diff changeset
301 -- client needs to be revoked
b8b2bf0c1b4b mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents: 5247
diff changeset
302 local function client_subset(client)
5511
0860497152af mod_http_oauth2: Record hash of client_id to allow future verification
Kim Alvefur <zash@zash.se>
parents: 5510
diff changeset
303 return {
0860497152af mod_http_oauth2: Record hash of client_id to allow future verification
Kim Alvefur <zash@zash.se>
parents: 5510
diff changeset
304 name = client.client_name;
0860497152af mod_http_oauth2: Record hash of client_id to allow future verification
Kim Alvefur <zash@zash.se>
parents: 5510
diff changeset
305 uri = client.client_uri;
0860497152af mod_http_oauth2: Record hash of client_id to allow future verification
Kim Alvefur <zash@zash.se>
parents: 5510
diff changeset
306 id = client.software_id;
0860497152af mod_http_oauth2: Record hash of client_id to allow future verification
Kim Alvefur <zash@zash.se>
parents: 5510
diff changeset
307 version = client.software_version;
0860497152af mod_http_oauth2: Record hash of client_id to allow future verification
Kim Alvefur <zash@zash.se>
parents: 5510
diff changeset
308 hash = client.client_hash;
0860497152af mod_http_oauth2: Record hash of client_id to allow future verification
Kim Alvefur <zash@zash.se>
parents: 5510
diff changeset
309 };
5248
b8b2bf0c1b4b mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents: 5247
diff changeset
310 end
b8b2bf0c1b4b mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents: 5247
diff changeset
311
6323
4f9b42c53d0f mod_http_oauth2: Check grant type before issuing refresh token
Kim Alvefur <zash@zash.se>
parents: 6322
diff changeset
312 local function may_issue_refresh_token(client, scope_string)
4f9b42c53d0f mod_http_oauth2: Check grant type before issuing refresh token
Kim Alvefur <zash@zash.se>
parents: 6322
diff changeset
313 return array_contains(client.grant_types, "refresh_token") and array_contains(parse_scopes(scope_string), "offline_access");
4f9b42c53d0f mod_http_oauth2: Check grant type before issuing refresh token
Kim Alvefur <zash@zash.se>
parents: 6322
diff changeset
314 end
4f9b42c53d0f mod_http_oauth2: Check grant type before issuing refresh token
Kim Alvefur <zash@zash.se>
parents: 6322
diff changeset
315
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
316 local function new_access_token(token_jid, role, scope_string, client, id_token, refresh_token_info)
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
317 local token_data = { oauth2_scopes = scope_string, oauth2_client = nil };
5248
b8b2bf0c1b4b mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents: 5247
diff changeset
318 if client then
5254
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
319 token_data.oauth2_client = client_subset(client);
5248
b8b2bf0c1b4b mod_http_oauth2: Record details of OAuth client a token is issued to
Kim Alvefur <zash@zash.se>
parents: 5247
diff changeset
320 end
5254
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
321 if next(token_data) == nil then
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
322 token_data = nil;
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
323 end
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
324
5280
eb482defd9b0 mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents: 5279
diff changeset
325 local grant = refresh_token_info and refresh_token_info.grant;
eb482defd9b0 mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents: 5279
diff changeset
326 if not grant then
eb482defd9b0 mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents: 5279
diff changeset
327 -- No existing grant, create one
5669
d67980d9e12d mod_http_oauth2: Apply refresh token ttl to refresh token instead of grant
Kim Alvefur <zash@zash.se>
parents: 5666
diff changeset
328 grant = tokens.create_grant(token_jid, token_jid, nil, token_data);
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
329 end
5280
eb482defd9b0 mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents: 5279
diff changeset
330
5623
59d5fc50f602 mod_http_oauth2: Implement refresh token rotation
Kim Alvefur <zash@zash.se>
parents: 5621
diff changeset
331 if refresh_token_info then
59d5fc50f602 mod_http_oauth2: Implement refresh token rotation
Kim Alvefur <zash@zash.se>
parents: 5621
diff changeset
332 -- out with the old refresh tokens
59d5fc50f602 mod_http_oauth2: Implement refresh token rotation
Kim Alvefur <zash@zash.se>
parents: 5621
diff changeset
333 local ok, err = tokens.revoke_token(refresh_token_info.token);
59d5fc50f602 mod_http_oauth2: Implement refresh token rotation
Kim Alvefur <zash@zash.se>
parents: 5621
diff changeset
334 if not ok then
59d5fc50f602 mod_http_oauth2: Implement refresh token rotation
Kim Alvefur <zash@zash.se>
parents: 5621
diff changeset
335 module:log("error", "Could not revoke refresh token: %s", err);
59d5fc50f602 mod_http_oauth2: Implement refresh token rotation
Kim Alvefur <zash@zash.se>
parents: 5621
diff changeset
336 return 500;
59d5fc50f602 mod_http_oauth2: Implement refresh token rotation
Kim Alvefur <zash@zash.se>
parents: 5621
diff changeset
337 end
59d5fc50f602 mod_http_oauth2: Implement refresh token rotation
Kim Alvefur <zash@zash.se>
parents: 5621
diff changeset
338 end
59d5fc50f602 mod_http_oauth2: Implement refresh token rotation
Kim Alvefur <zash@zash.se>
parents: 5621
diff changeset
339 -- in with the new refresh token
6317
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
340 local refresh_token;
6323
4f9b42c53d0f mod_http_oauth2: Check grant type before issuing refresh token
Kim Alvefur <zash@zash.se>
parents: 6322
diff changeset
341 if refresh_token_info ~= false and may_issue_refresh_token(client, scope_string) then
6317
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
342 refresh_token = tokens.create_token(token_jid, grant.id, nil, default_refresh_ttl, "oauth2-refresh");
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
343 end
5623
59d5fc50f602 mod_http_oauth2: Implement refresh token rotation
Kim Alvefur <zash@zash.se>
parents: 5621
diff changeset
344
5467
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
345 if role == "xmpp" then
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
346 -- Special scope meaning the users default role.
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
347 local user_default_role = usermanager.get_user_role(jid.node(token_jid), module.host);
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
348 role = user_default_role and user_default_role.name;
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
349 end
1c78a97a1091 mod_http_oauth2: Add a special "xmpp" scope that grants the users' default role
Kim Alvefur <zash@zash.se>
parents: 5466
diff changeset
350
5451
6705f2a09702 mod_http_oauth2: Reference grant by id instead of value
Kim Alvefur <zash@zash.se>
parents: 5450
diff changeset
351 local access_token, access_token_info = tokens.create_token(token_jid, grant.id, role, default_access_ttl, "oauth2");
5280
eb482defd9b0 mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents: 5279
diff changeset
352
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
353 local expires_at = access_token_info.expires;
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
354 return {
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
355 token_type = "bearer";
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
356 access_token = access_token;
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
357 expires_in = expires_at and (expires_at - os.time()) or nil;
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
358 scope = scope_string;
5257
b2120fb4a279 mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents: 5256
diff changeset
359 id_token = id_token;
5280
eb482defd9b0 mod_http_oauth2: Update to use new API of Prosody mod_tokenauth @ 601d9a375b86
Matthew Wild <mwild1@gmail.com>
parents: 5279
diff changeset
360 refresh_token = refresh_token or nil;
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
361 };
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
362 end
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
363
5461
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
364 local function normalize_loopback(uri)
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
365 local u = url.parse(uri);
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
366 if u.scheme == "http" and loopbacks:contains(u.host) then
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
367 u.authority = nil;
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
368 u.host = "::1";
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
369 u.port = nil;
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
370 return url.build(u);
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
371 end
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
372 -- else, not a valid loopback uri
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
373 end
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
374
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
375 local function get_redirect_uri(client, query_redirect_uri) -- record client, string : string
5219
25e824f64fd3 mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents: 5218
diff changeset
376 if not query_redirect_uri then
25e824f64fd3 mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents: 5218
diff changeset
377 if #client.redirect_uris ~= 1 then
25e824f64fd3 mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents: 5218
diff changeset
378 -- Client registered multiple URIs, it needs specify which one to use
25e824f64fd3 mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents: 5218
diff changeset
379 return;
25e824f64fd3 mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents: 5218
diff changeset
380 end
25e824f64fd3 mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents: 5218
diff changeset
381 -- When only a single URI is registered, that's the default
25e824f64fd3 mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents: 5218
diff changeset
382 return client.redirect_uris[1];
25e824f64fd3 mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents: 5218
diff changeset
383 end
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
384 if query_redirect_uri == device_uri and client.grant_types then
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
385 for _, grant_type in ipairs(client.grant_types) do
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
386 if grant_type == device_uri then
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
387 return query_redirect_uri;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
388 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
389 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
390 -- Tried to use device authorization flow without registering it.
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
391 return;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
392 end
5219
25e824f64fd3 mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents: 5218
diff changeset
393 -- Verify the client-provided URI matches one previously registered
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
394 for _, redirect_uri in ipairs(client.redirect_uris) do
5219
25e824f64fd3 mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents: 5218
diff changeset
395 if query_redirect_uri == redirect_uri then
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
396 return redirect_uri
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
397 end
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
398 end
5461
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
399 -- The authorization server MUST allow any port to be specified at the time
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
400 -- of the request for loopback IP redirect URIs, to accommodate clients that
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
401 -- obtain an available ephemeral port from the operating system at the time
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
402 -- of the request.
5460
c0d62c1b4424 mod_http_oauth2: Add FIXME about loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5459
diff changeset
403 -- https://www.ietf.org/archive/id/draft-ietf-oauth-v2-1-08.html#section-8.4.2
5461
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
404 local loopback_redirect_uri = normalize_loopback(query_redirect_uri);
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
405 if loopback_redirect_uri then
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
406 for _, redirect_uri in ipairs(client.redirect_uris) do
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
407 if loopback_redirect_uri == normalize_loopback(redirect_uri) then
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
408 return query_redirect_uri;
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
409 end
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
410 end
06640647d193 mod_http_oauth2: Fix use of arbitrary ports in loopback redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5460
diff changeset
411 end
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
412 end
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
413
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
414 local grant_type_handlers = {};
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
415 local response_type_handlers = {};
5383
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
416 local verifier_transforms = {};
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
417
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
418 function grant_type_handlers.implicit()
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
419 -- Placeholder to make discovery work correctly.
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
420 -- Access tokens are delivered via redirect when using the implict flow, not
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
421 -- via the token endpoint, so how did you get here?
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
422 return oauth_error("invalid_request");
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
423 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
424
6237
4f0ed0e3ad5a mod_http_oauth2: Require client authentication for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6207
diff changeset
425 local function make_client_secret(client_id) --> client_secret
6270
9014c95c4549 mod_http_oauth2: Fix indentation
Kim Alvefur <zash@zash.se>
parents: 6269
diff changeset
426 return hashes.hmac_sha256(verification_key, client_id, true);
6237
4f0ed0e3ad5a mod_http_oauth2: Require client authentication for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6207
diff changeset
427 end
4f0ed0e3ad5a mod_http_oauth2: Require client authentication for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6207
diff changeset
428
4f0ed0e3ad5a mod_http_oauth2: Require client authentication for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6207
diff changeset
429 local function verify_client_secret(client_id, client_secret)
6270
9014c95c4549 mod_http_oauth2: Fix indentation
Kim Alvefur <zash@zash.se>
parents: 6269
diff changeset
430 return hashes.equals(make_client_secret(client_id), client_secret);
6237
4f0ed0e3ad5a mod_http_oauth2: Require client authentication for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6207
diff changeset
431 end
4f0ed0e3ad5a mod_http_oauth2: Require client authentication for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6207
diff changeset
432
6269
2505542c6c50 mod_http_oauth2: Deduplicate client authentication
Kim Alvefur <zash@zash.se>
parents: 6240
diff changeset
433 function grant_type_handlers.password(params, client)
6240
ab14e7ecb82f mod_http_oauth2: Allow JIDs as username for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6239
diff changeset
434 local request_username
ab14e7ecb82f mod_http_oauth2: Allow JIDs as username for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6239
diff changeset
435
ab14e7ecb82f mod_http_oauth2: Allow JIDs as username for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6239
diff changeset
436 if expect_username_jid then
6288
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
437 local request_jid = params.username;
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
438 if not request_jid then
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
439 return oauth_error("invalid_request", "missing 'username' (JID)");
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
440 end
6271
b63202d66238 mod_http_oauth2: Remove unused variable [luacheck]
Kim Alvefur <zash@zash.se>
parents: 6270
diff changeset
441 local _request_username, request_host = jid.prepped_split(request_jid);
6240
ab14e7ecb82f mod_http_oauth2: Allow JIDs as username for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6239
diff changeset
442
ab14e7ecb82f mod_http_oauth2: Allow JIDs as username for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6239
diff changeset
443 if not (_request_username and request_host) or request_host ~= module.host then
ab14e7ecb82f mod_http_oauth2: Allow JIDs as username for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6239
diff changeset
444 return oauth_error("invalid_request", "invalid JID");
ab14e7ecb82f mod_http_oauth2: Allow JIDs as username for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6239
diff changeset
445 end
ab14e7ecb82f mod_http_oauth2: Allow JIDs as username for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6239
diff changeset
446
ab14e7ecb82f mod_http_oauth2: Allow JIDs as username for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6239
diff changeset
447 request_username = _request_username
ab14e7ecb82f mod_http_oauth2: Allow JIDs as username for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6239
diff changeset
448 else
6288
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
449 request_username = params.username;
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
450 if not request_username then
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
451 return oauth_error("invalid_request", "missing 'username'");
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
452 end
6240
ab14e7ecb82f mod_http_oauth2: Allow JIDs as username for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6239
diff changeset
453 end
ab14e7ecb82f mod_http_oauth2: Allow JIDs as username for password grant
magicfelix <felix@felix-zauberer.de>
parents: 6239
diff changeset
454
6288
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
455 local request_password = params.password;
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
456 if not request_password then
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
457 return oauth_error("invalid_request", "missing 'password'");
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
458 end
4340
7cd3b7ec59e9 mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents: 4276
diff changeset
459
6289
7e4238d2989c mod_http_oauth2: Fire authentication events in password grant
Kim Alvefur <zash@zash.se>
parents: 6288
diff changeset
460 local auth_event = {
7e4238d2989c mod_http_oauth2: Fire authentication events in password grant
Kim Alvefur <zash@zash.se>
parents: 6288
diff changeset
461 session = {
7e4238d2989c mod_http_oauth2: Fire authentication events in password grant
Kim Alvefur <zash@zash.se>
parents: 6288
diff changeset
462 type = "oauth2";
7e4238d2989c mod_http_oauth2: Fire authentication events in password grant
Kim Alvefur <zash@zash.se>
parents: 6288
diff changeset
463 ip = "::";
7e4238d2989c mod_http_oauth2: Fire authentication events in password grant
Kim Alvefur <zash@zash.se>
parents: 6288
diff changeset
464 username = request_username;
7e4238d2989c mod_http_oauth2: Fire authentication events in password grant
Kim Alvefur <zash@zash.se>
parents: 6288
diff changeset
465 host = module.host;
7e4238d2989c mod_http_oauth2: Fire authentication events in password grant
Kim Alvefur <zash@zash.se>
parents: 6288
diff changeset
466 log = module._log;
7e4238d2989c mod_http_oauth2: Fire authentication events in password grant
Kim Alvefur <zash@zash.se>
parents: 6288
diff changeset
467 sasl_handler = { username = request_username; selected = "x-oauth2-password" };
7e4238d2989c mod_http_oauth2: Fire authentication events in password grant
Kim Alvefur <zash@zash.se>
parents: 6288
diff changeset
468 client_id = client.client_name;
7e4238d2989c mod_http_oauth2: Fire authentication events in password grant
Kim Alvefur <zash@zash.se>
parents: 6288
diff changeset
469 };
7e4238d2989c mod_http_oauth2: Fire authentication events in password grant
Kim Alvefur <zash@zash.se>
parents: 6288
diff changeset
470 };
7e4238d2989c mod_http_oauth2: Fire authentication events in password grant
Kim Alvefur <zash@zash.se>
parents: 6288
diff changeset
471
6238
c1b94dd6e53b mod_http_oauth2: Change password grant to take username instead of JID [BC]
Kim Alvefur <zash@zash.se>
parents: 6237
diff changeset
472 if not usermanager.test_password(request_username, module.host, request_password) then
6289
7e4238d2989c mod_http_oauth2: Fire authentication events in password grant
Kim Alvefur <zash@zash.se>
parents: 6288
diff changeset
473 module:fire_event("authentication-failure", auth_event);
4340
7cd3b7ec59e9 mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents: 4276
diff changeset
474 return oauth_error("invalid_grant", "incorrect credentials");
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
475 end
4340
7cd3b7ec59e9 mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents: 4276
diff changeset
476
6289
7e4238d2989c mod_http_oauth2: Fire authentication events in password grant
Kim Alvefur <zash@zash.se>
parents: 6288
diff changeset
477 module:fire_event("authentication-success", auth_event);
7e4238d2989c mod_http_oauth2: Fire authentication events in password grant
Kim Alvefur <zash@zash.se>
parents: 6288
diff changeset
478
6238
c1b94dd6e53b mod_http_oauth2: Change password grant to take username instead of JID [BC]
Kim Alvefur <zash@zash.se>
parents: 6237
diff changeset
479 local granted_jid = jid.join(request_username, module.host);
5256
44f7edd4f845 mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents: 5255
diff changeset
480 local granted_scopes, granted_role = filter_scopes(request_username, params.scope);
6239
a931a95e363e mod_http_oauth2: Pass client to token to enable introspection
magicfelix <felix@felix-zauberer.de>
parents: 6238
diff changeset
481 return json.encode(new_access_token(granted_jid, granted_role, granted_scopes, client));
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
482 end
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
483
5257
b2120fb4a279 mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents: 5256
diff changeset
484 function response_type_handlers.code(client, params, granted_jid, id_token)
5191
f5a58cbe86e4 mod_http_oauth2: Derive scope from correct user details
Kim Alvefur <zash@zash.se>
parents: 5190
diff changeset
485 local request_username, request_host = jid.split(granted_jid);
5256
44f7edd4f845 mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents: 5255
diff changeset
486 if not request_host or request_host ~= module.host then
44f7edd4f845 mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents: 5255
diff changeset
487 return oauth_error("invalid_request", "invalid JID");
44f7edd4f845 mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents: 5255
diff changeset
488 end
44f7edd4f845 mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents: 5255
diff changeset
489 local granted_scopes, granted_role = filter_scopes(request_username, params.scope);
4340
7cd3b7ec59e9 mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents: 4276
diff changeset
490
5819
93d6e9026c1b mod_http_oauth2: Do not enforce PKCE on Device and OOB flows
Kim Alvefur <zash@zash.se>
parents: 5794
diff changeset
491 local redirect_uri = get_redirect_uri(client, params.redirect_uri);
93d6e9026c1b mod_http_oauth2: Do not enforce PKCE on Device and OOB flows
Kim Alvefur <zash@zash.se>
parents: 5794
diff changeset
492
93d6e9026c1b mod_http_oauth2: Do not enforce PKCE on Device and OOB flows
Kim Alvefur <zash@zash.se>
parents: 5794
diff changeset
493 if pkce_required and not params.code_challenge and redirect_uri ~= device_uri and redirect_uri ~= oob_uri then
5383
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
494 return oauth_error("invalid_request", "PKCE required");
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
495 end
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
496
5647
ef0a283507c9 mod_http_oauth2: Make storage of various code more consistent
Kim Alvefur <zash@zash.se>
parents: 5646
diff changeset
497 local prefix = "authorization_code:";
5243
d5dc8edb2695 mod_http_oauth2: Use more compact IDs
Kim Alvefur <zash@zash.se>
parents: 5242
diff changeset
498 local code = id.medium();
5819
93d6e9026c1b mod_http_oauth2: Do not enforce PKCE on Device and OOB flows
Kim Alvefur <zash@zash.se>
parents: 5794
diff changeset
499 if redirect_uri == device_uri then
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
500 local is_device, device_state = verify_device_token(params.state);
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
501 if is_device then
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
502 -- reconstruct the device_code
5647
ef0a283507c9 mod_http_oauth2: Make storage of various code more consistent
Kim Alvefur <zash@zash.se>
parents: 5646
diff changeset
503 prefix = "device_code:";
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
504 code = b64url(hashes.hmac_sha256(verification_key, device_state.user_code));
5646
9aace51c3637 mod_http_oauth2: Bail on invalid or expired device flow state token
Kim Alvefur <zash@zash.se>
parents: 5644
diff changeset
505 else
9aace51c3637 mod_http_oauth2: Bail on invalid or expired device flow state token
Kim Alvefur <zash@zash.se>
parents: 5644
diff changeset
506 return oauth_error("invalid_request");
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
507 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
508 end
5647
ef0a283507c9 mod_http_oauth2: Make storage of various code more consistent
Kim Alvefur <zash@zash.se>
parents: 5646
diff changeset
509 local ok = codes:set(prefix.. params.client_id .. "#" .. code, {
5213
dc0f502c12f1 mod_http_oauth2: Fix authorization code logic
Kim Alvefur <zash@zash.se>
parents: 5210
diff changeset
510 expires = os.time() + 600;
4340
7cd3b7ec59e9 mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents: 4276
diff changeset
511 granted_jid = granted_jid;
7cd3b7ec59e9 mod_http_oauth2: Rudimentary support for scopes (but not really)
Matthew Wild <mwild1@gmail.com>
parents: 4276
diff changeset
512 granted_scopes = granted_scopes;
5254
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
513 granted_role = granted_role;
5383
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
514 challenge = params.code_challenge;
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
515 challenge_method = params.code_challenge_method;
5257
b2120fb4a279 mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents: 5256
diff changeset
516 id_token = id_token;
4670
1b81b7269858 mod_http_oauth2: Gracefully handle cache write failure
Kim Alvefur <zash@zash.se>
parents: 4669
diff changeset
517 });
1b81b7269858 mod_http_oauth2: Gracefully handle cache write failure
Kim Alvefur <zash@zash.se>
parents: 4669
diff changeset
518 if not ok then
5476
575f52b15f5a mod_http_oauth2: Return OAuth error for authz code store error
Kim Alvefur <zash@zash.se>
parents: 5475
diff changeset
519 return oauth_error("temporarily_unavailable");
4670
1b81b7269858 mod_http_oauth2: Gracefully handle cache write failure
Kim Alvefur <zash@zash.se>
parents: 4669
diff changeset
520 end
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
521
5458
813fe4f76286 mod_http_oauth2: Do minimal validation of private-use URI schemes
Kim Alvefur <zash@zash.se>
parents: 5457
diff changeset
522 if redirect_uri == oob_uri then
5495
7998b49d6512 mod_http_oauth2: Create proper template for OOB code delivery
Kim Alvefur <zash@zash.se>
parents: 5480
diff changeset
523 return render_page(templates.oob, { client = client; authorization_code = code }, true);
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
524 elseif redirect_uri == device_uri then
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
525 return render_page(templates.device, { client = client }, true);
5219
25e824f64fd3 mod_http_oauth2: Improve handling of redirect_uri matching and fallback
Matthew Wild <mwild1@gmail.com>
parents: 5218
diff changeset
526 elseif not redirect_uri then
5462
f6d8830a83fe mod_http_oauth2: Return proper OAuth error for invalid redirect URI
Kim Alvefur <zash@zash.se>
parents: 5461
diff changeset
527 return oauth_error("invalid_redirect_uri");
5188
7c531137a553 mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents: 5187
diff changeset
528 end
7c531137a553 mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents: 5187
diff changeset
529
7c531137a553 mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents: 5187
diff changeset
530 local redirect = url.parse(redirect_uri);
7c531137a553 mod_http_oauth2: Implement OOB special redirect URI in code flow
Kim Alvefur <zash@zash.se>
parents: 5187
diff changeset
531
5513
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
532 local query = strict_formdecode(redirect.query);
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
533 if type(query) ~= "table" then query = {}; end
5192
03aa9baa9ac3 mod_http_oauth2: Add support for 'iss' authz response parameter (RFC 9207)
Matthew Wild <mwild1@gmail.com>
parents: 5191
diff changeset
534 table.insert(query, { name = "code", value = code });
5207
c72e3b0914e8 mod_http_oauth: Factor out issuer URL calculation to a helper function
Matthew Wild <mwild1@gmail.com>
parents: 5206
diff changeset
535 table.insert(query, { name = "iss", value = get_issuer() });
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
536 if params.state then
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
537 table.insert(query, { name = "state", value = params.state });
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
538 end
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
539 redirect.query = http.formencode(query);
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
540
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
541 return {
5210
898575a0c6f3 mod_http_oauth2: Switch to '303 See Other' redirects
Matthew Wild <mwild1@gmail.com>
parents: 5209
diff changeset
542 status_code = 303;
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
543 headers = {
5509
ae007be8a6bd mod_http_oauth2: Add Cache-Control and Pragma headers per by RFC 6749
Kim Alvefur <zash@zash.se>
parents: 5502
diff changeset
544 cache_control = "no-store";
ae007be8a6bd mod_http_oauth2: Add Cache-Control and Pragma headers per by RFC 6749
Kim Alvefur <zash@zash.se>
parents: 5502
diff changeset
545 pragma = "no-cache";
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
546 location = url.build(redirect);
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
547 };
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
548 }
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
549 end
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
550
5186
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
551 -- Implicit flow
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
552 function response_type_handlers.token(client, params, granted_jid)
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
553 local request_username, request_host = jid.split(granted_jid);
5256
44f7edd4f845 mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents: 5255
diff changeset
554 if not request_host or request_host ~= module.host then
44f7edd4f845 mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents: 5255
diff changeset
555 return oauth_error("invalid_request", "invalid JID");
44f7edd4f845 mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents: 5255
diff changeset
556 end
44f7edd4f845 mod_http_oauth2: Reject non-local hosts in more code paths
Kim Alvefur <zash@zash.se>
parents: 5255
diff changeset
557 local granted_scopes, granted_role = filter_scopes(request_username, params.scope);
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
558 local token_info = new_access_token(granted_jid, granted_role, granted_scopes, client, nil);
5186
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
559
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
560 local redirect = url.parse(get_redirect_uri(client, params.redirect_uri));
5463
dacde53467f3 mod_http_oauth2: Proper OAuth error for invalid redirect URI in implicit flow too
Kim Alvefur <zash@zash.se>
parents: 5462
diff changeset
561 if not redirect then return oauth_error("invalid_redirect_uri"); end
5186
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
562 token_info.state = params.state;
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
563 redirect.fragment = http.formencode(token_info);
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
564
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
565 return {
5210
898575a0c6f3 mod_http_oauth2: Switch to '303 See Other' redirects
Matthew Wild <mwild1@gmail.com>
parents: 5209
diff changeset
566 status_code = 303;
5186
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
567 headers = {
5509
ae007be8a6bd mod_http_oauth2: Add Cache-Control and Pragma headers per by RFC 6749
Kim Alvefur <zash@zash.se>
parents: 5502
diff changeset
568 cache_control = "no-store";
ae007be8a6bd mod_http_oauth2: Add Cache-Control and Pragma headers per by RFC 6749
Kim Alvefur <zash@zash.se>
parents: 5502
diff changeset
569 pragma = "no-cache";
5186
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
570 location = url.build(redirect);
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
571 };
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
572 }
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
573 end
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
574
6269
2505542c6c50 mod_http_oauth2: Deduplicate client authentication
Kim Alvefur <zash@zash.se>
parents: 6240
diff changeset
575 function grant_type_handlers.authorization_code(params, client)
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
576 if not params.code then return oauth_error("invalid_request", "missing 'code'"); end
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
577 if params.scope and params.scope ~= "" then
5450
d2594bbf7c36 mod_http_oauth2: Scope FIXMEs
Kim Alvefur <zash@zash.se>
parents: 5449
diff changeset
578 -- FIXME allow a subset of granted scopes
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
579 return oauth_error("invalid_scope", "unknown scope requested");
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
580 end
5614
ad9b8f659c96 mod_http_oauth2: Namespace the various codes to minimize confusion
Kim Alvefur <zash@zash.se>
parents: 5612
diff changeset
581 local code, err = codes:get("authorization_code:" .. params.client_id .. "#" .. params.code);
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
582 if err then error(err); end
5214
d5492bc861f6 mod_http_oauth2: Remove authorization codes after use
Kim Alvefur <zash@zash.se>
parents: 5213
diff changeset
583 -- MUST NOT use the authorization code more than once, so remove it to
d5492bc861f6 mod_http_oauth2: Remove authorization codes after use
Kim Alvefur <zash@zash.se>
parents: 5213
diff changeset
584 -- prevent a second attempted use
5550
4fda06be6b08 mod_http_oauth2: Make note about handling repeated
Kim Alvefur <zash@zash.se>
parents: 5549
diff changeset
585 -- TODO if a second attempt *is* made, revoke any tokens issued
5614
ad9b8f659c96 mod_http_oauth2: Namespace the various codes to minimize confusion
Kim Alvefur <zash@zash.se>
parents: 5612
diff changeset
586 codes:set("authorization_code:" .. params.client_id .. "#" .. params.code, nil);
4269
143515d0b212 mod_http_oauth2: Factor out authorization code validity decision
Kim Alvefur <zash@zash.se>
parents: 4265
diff changeset
587 if not code or type(code) ~= "table" or code_expired(code) then
4260
c539334dd01a mod_http_oauth2: Rescope oauth client config into users' storage
Kim Alvefur <zash@zash.se>
parents: 4259
diff changeset
588 module:log("debug", "authorization_code invalid or expired: %q", code);
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
589 return oauth_error("invalid_client", "incorrect credentials");
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
590 end
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
591
5383
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
592 -- TODO Decide if the code should be removed or not when PKCE fails
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
593 local transform = verifier_transforms[code.challenge_method or "plain"];
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
594 if not transform then
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
595 return oauth_error("invalid_request", "unknown challenge transform method");
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
596 elseif transform(params.code_verifier) ~= code.challenge then
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
597 return oauth_error("invalid_grant", "incorrect credentials");
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
598 end
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
599
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
600 return json.encode(new_access_token(code.granted_jid, code.granted_role, code.granted_scopes, client, code.id_token));
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
601 end
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
602
6285
b460b2a65f0b mod_http_oauth2: Remove now redundant client_id check from remaining grant handlers
Kim Alvefur <zash@zash.se>
parents: 6282
diff changeset
603 function grant_type_handlers.refresh_token(params, client)
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
604 if not params.refresh_token then return oauth_error("invalid_request", "missing 'refresh_token'"); end
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
605
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
606 local refresh_token_info = tokens.get_token_info(params.refresh_token);
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
607 if not refresh_token_info or refresh_token_info.purpose ~= "oauth2-refresh" then
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
608 return oauth_error("invalid_grant", "invalid refresh token");
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
609 end
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
610
5512
1fbc8718bed6 mod_http_oauth2: Bind refresh tokens to client
Kim Alvefur <zash@zash.se>
parents: 5511
diff changeset
611 local refresh_token_client = refresh_token_info.grant.data.oauth2_client;
1fbc8718bed6 mod_http_oauth2: Bind refresh tokens to client
Kim Alvefur <zash@zash.se>
parents: 5511
diff changeset
612 if not refresh_token_client.hash or refresh_token_client.hash ~= client.client_hash then
1fbc8718bed6 mod_http_oauth2: Bind refresh tokens to client
Kim Alvefur <zash@zash.se>
parents: 5511
diff changeset
613 module:log("warn", "OAuth client %q (%s) tried to use refresh token belonging to %q (%s)", client.client_name, client.client_hash,
1fbc8718bed6 mod_http_oauth2: Bind refresh tokens to client
Kim Alvefur <zash@zash.se>
parents: 5511
diff changeset
614 refresh_token_client.name, refresh_token_client.hash);
1fbc8718bed6 mod_http_oauth2: Bind refresh tokens to client
Kim Alvefur <zash@zash.se>
parents: 5511
diff changeset
615 return oauth_error("unauthorized_client", "incorrect credentials");
1fbc8718bed6 mod_http_oauth2: Bind refresh tokens to client
Kim Alvefur <zash@zash.se>
parents: 5511
diff changeset
616 end
1fbc8718bed6 mod_http_oauth2: Bind refresh tokens to client
Kim Alvefur <zash@zash.se>
parents: 5511
diff changeset
617
5446
dd7bddc87f98 mod_http_oauth2: Fix inclusion of role in refreshed access tokens
Kim Alvefur <zash@zash.se>
parents: 5445
diff changeset
618 local refresh_scopes = refresh_token_info.grant.data.oauth2_scopes;
5448
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
619
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
620 if params.scope then
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
621 local granted_scopes = set.new(parse_scopes(refresh_scopes));
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
622 local requested_scopes = parse_scopes(params.scope);
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
623 refresh_scopes = array.filter(requested_scopes, function(scope)
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
624 return granted_scopes:contains(scope);
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
625 end):concat(" ");
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
626 end
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
627
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
628 local username = jid.split(refresh_token_info.jid);
5446
dd7bddc87f98 mod_http_oauth2: Fix inclusion of role in refreshed access tokens
Kim Alvefur <zash@zash.se>
parents: 5445
diff changeset
629 local new_scopes, role = filter_scopes(username, refresh_scopes);
dd7bddc87f98 mod_http_oauth2: Fix inclusion of role in refreshed access tokens
Kim Alvefur <zash@zash.se>
parents: 5445
diff changeset
630
5279
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
631 -- new_access_token() requires the actual token
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
632 refresh_token_info.token = params.refresh_token;
2b858cccac8f mod_http_oauth2: Add support for refresh tokens
Matthew Wild <mwild1@gmail.com>
parents: 5278
diff changeset
633
5448
9d542e86e19a mod_http_oauth2: Allow requesting a subset of scopes on token refresh
Kim Alvefur <zash@zash.se>
parents: 5447
diff changeset
634 return json.encode(new_access_token(refresh_token_info.jid, role, new_scopes, client, nil, refresh_token_info));
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
635 end
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
636
6285
b460b2a65f0b mod_http_oauth2: Remove now redundant client_id check from remaining grant handlers
Kim Alvefur <zash@zash.se>
parents: 6282
diff changeset
637 grant_type_handlers[device_uri] = function(params, client)
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
638 if not params.device_code then return oauth_error("invalid_request", "missing 'device_code'"); end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
639
5647
ef0a283507c9 mod_http_oauth2: Make storage of various code more consistent
Kim Alvefur <zash@zash.se>
parents: 5646
diff changeset
640 local code = codes:get("device_code:" .. params.client_id .. "#" .. params.device_code);
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
641 if type(code) ~= "table" or code_expired(code) then
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
642 return oauth_error("expired_token");
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
643 elseif code.error then
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
644 return code.error;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
645 elseif not code.granted_jid then
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
646 return oauth_error("authorization_pending");
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
647 end
5647
ef0a283507c9 mod_http_oauth2: Make storage of various code more consistent
Kim Alvefur <zash@zash.se>
parents: 5646
diff changeset
648 codes:set("device_code:" .. params.client_id .. "#" .. params.device_code, nil);
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
649
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
650 return json.encode(new_access_token(code.granted_jid, code.granted_role, code.granted_scopes, client, code.id_token));
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
651 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
652
5383
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
653 -- RFC 7636 Proof Key for Code Exchange by OAuth Public Clients
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
654
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
655 function verifier_transforms.plain(code_verifier)
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
656 -- code_challenge = code_verifier
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
657 return code_verifier;
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
658 end
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
659
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
660 function verifier_transforms.S256(code_verifier)
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
661 -- code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier)))
5391
4aedce4fb95d mod_http_oauth2: Fix accidental uppercase in invocation of hash function
Kim Alvefur <zash@zash.se>
parents: 5390
diff changeset
662 return code_verifier and b64url(hashes.sha256(code_verifier));
5383
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
663 end
df11a2cbc7b7 mod_http_oauth2: Implement RFC 7628 Proof Key for Code Exchange
Kim Alvefur <zash@zash.se>
parents: 5382
diff changeset
664
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
665 -- Used to issue/verify short-lived tokens for the authorization process below
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
666 local new_user_token, verify_user_token = jwt.init("HS256", random.bytes(32), nil, { default_ttl = 600 });
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
667
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
668 -- From the given request, figure out if the user is authenticated and has granted consent yet
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
669 -- As this requires multiple steps (seek credentials, seek consent), we have a lot of state to
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
670 -- carry around across requests. We also need to protect against CSRF and session mix-up attacks
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
671 -- (e.g. the user may have multiple concurrent flows in progress, session cookies aren't unique
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
672 -- to one of them).
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
673 -- Our strategy here is to preserve the original query string (containing the authz request), and
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
674 -- encode the rest of the flow in form POSTs.
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
675 local function get_auth_state(request)
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
676 local form = request.method == "POST"
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
677 and request.body
5276
67777cb7353d mod_http_oauth2: Pedantic optimization
Kim Alvefur <zash@zash.se>
parents: 5273
diff changeset
678 and request.body ~= ""
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
679 and request.headers.content_type == "application/x-www-form-urlencoded"
5514
61b8d3eb91a4 mod_http_oauth2: Revert strict form check to allow consent of multiple scopes
Kim Alvefur <zash@zash.se>
parents: 5513
diff changeset
680 and http.formdecode(request.body);
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
681
5277
a1055024b94e mod_http_oauth2: Stricten check of urlencoded form data
Kim Alvefur <zash@zash.se>
parents: 5276
diff changeset
682 if type(form) ~= "table" then return {}; end
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
683
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
684 if not form.user_token then
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
685 -- First step: login
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
686 local username = encodings.stringprep.nodeprep(form.username);
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
687 local password = encodings.stringprep.saslprep(form.password);
5775
c27eaa7117d6 mod_http_oauth2: Fire authentication events on login form
Kim Alvefur <zash@zash.se>
parents: 5774
diff changeset
688 -- Many things hooked to authentication-{success,failure} don't expect
c27eaa7117d6 mod_http_oauth2: Fire authentication events on login form
Kim Alvefur <zash@zash.se>
parents: 5774
diff changeset
689 -- non-XMPP sessions so here's something close enough...
c27eaa7117d6 mod_http_oauth2: Fire authentication events on login form
Kim Alvefur <zash@zash.se>
parents: 5774
diff changeset
690 local auth_event = {
c27eaa7117d6 mod_http_oauth2: Fire authentication events on login form
Kim Alvefur <zash@zash.se>
parents: 5774
diff changeset
691 session = {
c27eaa7117d6 mod_http_oauth2: Fire authentication events on login form
Kim Alvefur <zash@zash.se>
parents: 5774
diff changeset
692 type = "http";
c27eaa7117d6 mod_http_oauth2: Fire authentication events on login form
Kim Alvefur <zash@zash.se>
parents: 5774
diff changeset
693 ip = request.ip;
c27eaa7117d6 mod_http_oauth2: Fire authentication events on login form
Kim Alvefur <zash@zash.se>
parents: 5774
diff changeset
694 conn = request.conn;
c27eaa7117d6 mod_http_oauth2: Fire authentication events on login form
Kim Alvefur <zash@zash.se>
parents: 5774
diff changeset
695 username = username;
c27eaa7117d6 mod_http_oauth2: Fire authentication events on login form
Kim Alvefur <zash@zash.se>
parents: 5774
diff changeset
696 host = module.host;
5794
72799c330986 mod_http_oauth2: Add logger to "session" for auth event
Kim Alvefur <zash@zash.se>
parents: 5793
diff changeset
697 log = request.log;
5775
c27eaa7117d6 mod_http_oauth2: Fire authentication events on login form
Kim Alvefur <zash@zash.se>
parents: 5774
diff changeset
698 sasl_handler = { username = username; selected = "x-www-form" };
c27eaa7117d6 mod_http_oauth2: Fire authentication events on login form
Kim Alvefur <zash@zash.se>
parents: 5774
diff changeset
699 client_id = request.headers.user_agent;
c27eaa7117d6 mod_http_oauth2: Fire authentication events on login form
Kim Alvefur <zash@zash.se>
parents: 5774
diff changeset
700 };
c27eaa7117d6 mod_http_oauth2: Fire authentication events on login form
Kim Alvefur <zash@zash.se>
parents: 5774
diff changeset
701 };
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
702 if not (username and password) or not usermanager.test_password(username, module.host, password) then
5775
c27eaa7117d6 mod_http_oauth2: Fire authentication events on login form
Kim Alvefur <zash@zash.se>
parents: 5774
diff changeset
703 module:fire_event("authentication-failure", auth_event);
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
704 return {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
705 error = "Invalid username/password";
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
706 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
707 end
5775
c27eaa7117d6 mod_http_oauth2: Fire authentication events on login form
Kim Alvefur <zash@zash.se>
parents: 5774
diff changeset
708 module:fire_event("authentication-success", auth_event);
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
709 return {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
710 user = {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
711 username = username;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
712 host = module.host;
5853
b109773ce6fe mod_http_oauth2: Reuse JWT issuance time as substitute for auth time
Kim Alvefur <zash@zash.se>
parents: 5822
diff changeset
713 token = new_user_token({ username = username; host = module.host; amr = { "pwd" } });
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
714 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
715 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
716 elseif form.user_token and form.consent then
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
717 -- Second step: consent
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
718 local ok, user = verify_user_token(form.user_token);
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
719 if not ok then
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
720 return {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
721 error = user == "token-expired" and "Session expired - try again" or nil;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
722 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
723 end
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
724
5447
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
725 local scopes = array():append(form):filter(function(field)
5424
b45d9a81b3da mod_http_oauth2: Revert role selector, going to try something else
Kim Alvefur <zash@zash.se>
parents: 5423
diff changeset
726 return field.name == "scope";
5447
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
727 end):pluck("value");
5271
3a1df3adad0c mod_http_oauth2: Allow user to decide which requested scopes to grant
Kim Alvefur <zash@zash.se>
parents: 5268
diff changeset
728
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
729 user.token = form.user_token;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
730 return {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
731 user = user;
5447
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
732 scopes = scopes;
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
733 consent = form.consent == "granted";
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
734 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
735 end
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
736
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
737 return {};
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
738 end
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
739
5222
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
740 local function get_request_credentials(request)
5224
cd5cf4cc6304 mod_http_oauth2: Fail early when no authorization header present
Matthew Wild <mwild1@gmail.com>
parents: 5223
diff changeset
741 if not request.headers.authorization then return; end
cd5cf4cc6304 mod_http_oauth2: Fail early when no authorization header present
Matthew Wild <mwild1@gmail.com>
parents: 5223
diff changeset
742
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
743 local auth_type, auth_data = string.match(request.headers.authorization, "^(%S+)%s(.+)$");
5963
46394b327d17 mod_http_oauth2: Guard against malformed authorization header
Kim Alvefur <zash@zash.se>
parents: 5959
diff changeset
744 if not auth_type then return nil; end
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
745
5959
ca3479c67e48 mod_http_oauth2: HTTP authentication schemes are case-insensitive
Kim Alvefur <zash@zash.se>
parents: 5882
diff changeset
746 -- As described in Section 2.3 of [RFC5234], the string Bearer is case-insensitive.
ca3479c67e48 mod_http_oauth2: HTTP authentication schemes are case-insensitive
Kim Alvefur <zash@zash.se>
parents: 5882
diff changeset
747 -- https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-11#section-5.1.1
ca3479c67e48 mod_http_oauth2: HTTP authentication schemes are case-insensitive
Kim Alvefur <zash@zash.se>
parents: 5882
diff changeset
748 auth_type = auth_type:lower();
ca3479c67e48 mod_http_oauth2: HTTP authentication schemes are case-insensitive
Kim Alvefur <zash@zash.se>
parents: 5882
diff changeset
749
ca3479c67e48 mod_http_oauth2: HTTP authentication schemes are case-insensitive
Kim Alvefur <zash@zash.se>
parents: 5882
diff changeset
750 if auth_type == "basic" then
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
751 local creds = base64.decode(auth_data);
5222
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
752 if not creds then return; end
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
753 local username, password = string.match(creds, "^([^:]+):(.*)$");
5222
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
754 if not username then return; end
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
755 return {
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
756 type = "basic";
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
757 username = username;
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
758 password = password;
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
759 };
5959
ca3479c67e48 mod_http_oauth2: HTTP authentication schemes are case-insensitive
Kim Alvefur <zash@zash.se>
parents: 5882
diff changeset
760 elseif auth_type == "bearer" then
5222
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
761 return {
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
762 type = "bearer";
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
763 bearer_token = auth_data;
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
764 };
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
765 end
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
766
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
767 return nil;
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
768 end
578a72982bb2 mod_http_oauth2: Separate extracting credentials from requests and verifying
Matthew Wild <mwild1@gmail.com>
parents: 5221
diff changeset
769
3920
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
770 if module:get_host_type() == "component" then
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
771 local component_secret = assert(module:get_option_string("component_secret"), "'component_secret' is a required setting when loaded on a Component");
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
772
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
773 function grant_type_handlers.password(params)
6288
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
774 local request_jid = params.username;
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
775 if not request_jid then
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
776 return oauth_error("invalid_request", "missing 'username' (JID)");
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
777 end
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
778 local request_password = params.password
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
779 if not request_password then
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
780 return oauth_error("invalid_request", "missing 'password'");
b7eb7d256939 mod_http_oauth2: Return instead of throwing errors
Kim Alvefur <zash@zash.se>
parents: 6287
diff changeset
781 end
3920
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
782 local request_username, request_host, request_resource = jid.prepped_split(request_jid);
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
783 if params.scope then
5450
d2594bbf7c36 mod_http_oauth2: Scope FIXMEs
Kim Alvefur <zash@zash.se>
parents: 5449
diff changeset
784 -- TODO shouldn't we support scopes / roles here?
3920
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
785 return oauth_error("invalid_scope", "unknown scope requested");
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
786 end
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
787 if not request_host or request_host ~= module.host then
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
788 return oauth_error("invalid_request", "invalid JID");
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
789 end
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
790 if request_password == component_secret then
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
791 local granted_jid = jid.join(request_username, request_host, request_resource);
5254
b0ccdd12a70d mod_http_oauth2: Prepare to handle multiple e.g. non-role scopes
Kim Alvefur <zash@zash.se>
parents: 5252
diff changeset
792 return json.encode(new_access_token(granted_jid, nil, nil, nil));
3920
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
793 end
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
794 return oauth_error("invalid_grant", "incorrect credentials");
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
795 end
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
796
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
797 -- TODO How would this make sense with components?
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
798 -- Have an admin authenticate maybe?
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
799 response_type_handlers.code = nil;
5186
fa3059e653fa mod_http_oauth2: Implement the Implicit flow
Kim Alvefur <zash@zash.se>
parents: 5185
diff changeset
800 response_type_handlers.token = nil;
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
801 grant_type_handlers.authorization_code = nil;
3920
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
802 end
cf92e3b30c18 mod_http_oauth2: Use component_secret setting as password on Components
Kim Alvefur <zash@zash.se>
parents: 3919
diff changeset
803
5472
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
804 local function render_error(err)
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
805 return render_page(templates.error, { error = err });
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
806 end
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
807
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
808 -- OAuth errors should be returned to the client if possible, i.e. by
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
809 -- appending the error information to the redirect_uri and sending the
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
810 -- redirect to the user-agent. In some cases we can't do this, e.g. if
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
811 -- the redirect_uri is missing or invalid. In those cases, we render an
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
812 -- error directly to the user-agent.
5477
5986e0edd7a3 mod_http_oauth2: Use validated redirect URI when returning errors to client
Kim Alvefur <zash@zash.se>
parents: 5476
diff changeset
813 local function error_response(request, redirect_uri, err)
6307
aae94f82c56e mod_http_oauth2: Refactor to return all errors to Device clients
Kim Alvefur <zash@zash.se>
parents: 6292
diff changeset
814 if not redirect_uri or redirect_uri == oob_uri then
5472
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
815 return render_error(err);
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
816 end
6307
aae94f82c56e mod_http_oauth2: Refactor to return all errors to Device clients
Kim Alvefur <zash@zash.se>
parents: 6292
diff changeset
817 local params = strict_formdecode(request.url.query);
aae94f82c56e mod_http_oauth2: Refactor to return all errors to Device clients
Kim Alvefur <zash@zash.se>
parents: 6292
diff changeset
818 if redirect_uri == device_uri then
aae94f82c56e mod_http_oauth2: Refactor to return all errors to Device clients
Kim Alvefur <zash@zash.se>
parents: 6292
diff changeset
819 local is_device, device_state = verify_device_token(params.state);
aae94f82c56e mod_http_oauth2: Refactor to return all errors to Device clients
Kim Alvefur <zash@zash.se>
parents: 6292
diff changeset
820 if is_device then
aae94f82c56e mod_http_oauth2: Refactor to return all errors to Device clients
Kim Alvefur <zash@zash.se>
parents: 6292
diff changeset
821 local device_code = b64url(hashes.hmac_sha256(verification_key, device_state.user_code));
aae94f82c56e mod_http_oauth2: Refactor to return all errors to Device clients
Kim Alvefur <zash@zash.se>
parents: 6292
diff changeset
822 local code = codes:get("device_code:" .. params.client_id .. "#" .. device_code);
6308
e1c54de06905 mod_http_oauth2: Handle case of device state having expired
Kim Alvefur <zash@zash.se>
parents: 6307
diff changeset
823 if type(code) == "table" then
e1c54de06905 mod_http_oauth2: Handle case of device state having expired
Kim Alvefur <zash@zash.se>
parents: 6307
diff changeset
824 code.error = err;
e1c54de06905 mod_http_oauth2: Handle case of device state having expired
Kim Alvefur <zash@zash.se>
parents: 6307
diff changeset
825 code.expires = os.time() + 60;
e1c54de06905 mod_http_oauth2: Handle case of device state having expired
Kim Alvefur <zash@zash.se>
parents: 6307
diff changeset
826 codes:set("device_code:" .. params.client_id .. "#" .. device_code, code);
e1c54de06905 mod_http_oauth2: Handle case of device state having expired
Kim Alvefur <zash@zash.se>
parents: 6307
diff changeset
827 end
6307
aae94f82c56e mod_http_oauth2: Refactor to return all errors to Device clients
Kim Alvefur <zash@zash.se>
parents: 6292
diff changeset
828 end
aae94f82c56e mod_http_oauth2: Refactor to return all errors to Device clients
Kim Alvefur <zash@zash.se>
parents: 6292
diff changeset
829 return render_error(err);
aae94f82c56e mod_http_oauth2: Refactor to return all errors to Device clients
Kim Alvefur <zash@zash.se>
parents: 6292
diff changeset
830 end
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
831 local redirect_query = url.parse(redirect_uri);
5229
c24a622a7b85 mod_http_oauth2: Fix appending of query parts in error redirects
Kim Alvefur <zash@zash.se>
parents: 5228
diff changeset
832 local sep = redirect_query.query and "&" or "?";
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
833 redirect_uri = redirect_uri
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
834 .. sep .. http.formencode(err.extra.oauth2_response)
6307
aae94f82c56e mod_http_oauth2: Refactor to return all errors to Device clients
Kim Alvefur <zash@zash.se>
parents: 6292
diff changeset
835 .. "&" .. http.formencode({ state = params.state, iss = get_issuer() });
5822
c75328aeaba3 mod_http_oauth2: Reduce log level for error delivery via redirect
Kim Alvefur <zash@zash.se>
parents: 5821
diff changeset
836 module:log("debug", "Sending error response to client via redirect to %s", redirect_uri);
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
837 return {
5210
898575a0c6f3 mod_http_oauth2: Switch to '303 See Other' redirects
Matthew Wild <mwild1@gmail.com>
parents: 5209
diff changeset
838 status_code = 303;
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
839 headers = {
5509
ae007be8a6bd mod_http_oauth2: Add Cache-Control and Pragma headers per by RFC 6749
Kim Alvefur <zash@zash.se>
parents: 5502
diff changeset
840 cache_control = "no-store";
ae007be8a6bd mod_http_oauth2: Add Cache-Control and Pragma headers per by RFC 6749
Kim Alvefur <zash@zash.se>
parents: 5502
diff changeset
841 pragma = "no-cache";
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
842 location = redirect_uri;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
843 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
844 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
845 end
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
846
5549
01a0b67a9afd mod_http_oauth2: Add TODO about disabling password grant
Kim Alvefur <zash@zash.se>
parents: 5548
diff changeset
847 local allowed_grant_type_handlers = module:get_option_set("allowed_oauth2_grant_types", {
01a0b67a9afd mod_http_oauth2: Add TODO about disabling password grant
Kim Alvefur <zash@zash.se>
parents: 5548
diff changeset
848 "authorization_code";
01a0b67a9afd mod_http_oauth2: Add TODO about disabling password grant
Kim Alvefur <zash@zash.se>
parents: 5548
diff changeset
849 "refresh_token";
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
850 device_uri;
5549
01a0b67a9afd mod_http_oauth2: Add TODO about disabling password grant
Kim Alvefur <zash@zash.se>
parents: 5548
diff changeset
851 })
5621
7565298aa197 mod_http_oauth2: Allow a shorter form of the device grant in config
Kim Alvefur <zash@zash.se>
parents: 5615
diff changeset
852 if allowed_grant_type_handlers:contains("device_code") then
7565298aa197 mod_http_oauth2: Allow a shorter form of the device grant in config
Kim Alvefur <zash@zash.se>
parents: 5615
diff changeset
853 -- expand short form because that URI is long
7565298aa197 mod_http_oauth2: Allow a shorter form of the device grant in config
Kim Alvefur <zash@zash.se>
parents: 5615
diff changeset
854 module:log("debug", "Expanding %q to %q in '%s'", "device_code", device_uri, "allowed_oauth2_grant_types");
7565298aa197 mod_http_oauth2: Allow a shorter form of the device grant in config
Kim Alvefur <zash@zash.se>
parents: 5615
diff changeset
855 allowed_grant_type_handlers:remove("device_code");
7565298aa197 mod_http_oauth2: Allow a shorter form of the device grant in config
Kim Alvefur <zash@zash.se>
parents: 5615
diff changeset
856 allowed_grant_type_handlers:add(device_uri);
7565298aa197 mod_http_oauth2: Allow a shorter form of the device grant in config
Kim Alvefur <zash@zash.se>
parents: 5615
diff changeset
857 end
5187
6a3c1febd7be mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents: 5186
diff changeset
858 for handler_type in pairs(grant_type_handlers) do
6a3c1febd7be mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents: 5186
diff changeset
859 if not allowed_grant_type_handlers:contains(handler_type) then
5230
ac252db71027 mod_http_oauth2: Log flows enabled and disabled
Kim Alvefur <zash@zash.se>
parents: 5229
diff changeset
860 module:log("debug", "Grant type %q disabled", handler_type);
5187
6a3c1febd7be mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents: 5186
diff changeset
861 grant_type_handlers[handler_type] = nil;
5230
ac252db71027 mod_http_oauth2: Log flows enabled and disabled
Kim Alvefur <zash@zash.se>
parents: 5229
diff changeset
862 else
ac252db71027 mod_http_oauth2: Log flows enabled and disabled
Kim Alvefur <zash@zash.se>
parents: 5229
diff changeset
863 module:log("debug", "Grant type %q enabled", handler_type);
5187
6a3c1febd7be mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents: 5186
diff changeset
864 end
6a3c1febd7be mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents: 5186
diff changeset
865 end
6a3c1febd7be mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents: 5186
diff changeset
866
6a3c1febd7be mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents: 5186
diff changeset
867 -- "token" aka implicit flow is considered insecure
6a3c1febd7be mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents: 5186
diff changeset
868 local allowed_response_type_handlers = module:get_option_set("allowed_oauth2_response_types", {"code"})
5198
2e8a7a0f932d mod_http_oauth2: Fix response type config
Kim Alvefur <zash@zash.se>
parents: 5196
diff changeset
869 for handler_type in pairs(response_type_handlers) do
2e8a7a0f932d mod_http_oauth2: Fix response type config
Kim Alvefur <zash@zash.se>
parents: 5196
diff changeset
870 if not allowed_response_type_handlers:contains(handler_type) then
5230
ac252db71027 mod_http_oauth2: Log flows enabled and disabled
Kim Alvefur <zash@zash.se>
parents: 5229
diff changeset
871 module:log("debug", "Response type %q disabled", handler_type);
5231
bef543068077 mod_http_oauth2: Fix to disable disabled response handlers correctly
Kim Alvefur <zash@zash.se>
parents: 5230
diff changeset
872 response_type_handlers[handler_type] = nil;
5230
ac252db71027 mod_http_oauth2: Log flows enabled and disabled
Kim Alvefur <zash@zash.se>
parents: 5229
diff changeset
873 else
ac252db71027 mod_http_oauth2: Log flows enabled and disabled
Kim Alvefur <zash@zash.se>
parents: 5229
diff changeset
874 module:log("debug", "Response type %q enabled", handler_type);
5187
6a3c1febd7be mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents: 5186
diff changeset
875 end
6a3c1febd7be mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents: 5186
diff changeset
876 end
6a3c1febd7be mod_http_oauth2: Add settings for allowed grant and response types
Kim Alvefur <zash@zash.se>
parents: 5186
diff changeset
877
5739
426c42c11f89 mod_http_oauth2: Make defaults more secure
Kim Alvefur <zash@zash.se>
parents: 5738
diff changeset
878 local allowed_challenge_methods = module:get_option_set("allowed_oauth2_code_challenge_methods", { "S256" })
5384
b40f29ec391a mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents: 5383
diff changeset
879 for handler_type in pairs(verifier_transforms) do
b40f29ec391a mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents: 5383
diff changeset
880 if not allowed_challenge_methods:contains(handler_type) then
b40f29ec391a mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents: 5383
diff changeset
881 module:log("debug", "Challenge method %q disabled", handler_type);
b40f29ec391a mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents: 5383
diff changeset
882 verifier_transforms[handler_type] = nil;
b40f29ec391a mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents: 5383
diff changeset
883 else
b40f29ec391a mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents: 5383
diff changeset
884 module:log("debug", "Challenge method %q enabled", handler_type);
b40f29ec391a mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents: 5383
diff changeset
885 end
b40f29ec391a mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents: 5383
diff changeset
886 end
b40f29ec391a mod_http_oauth2: Allow configuring PKCE challenge methods
Kim Alvefur <zash@zash.se>
parents: 5383
diff changeset
887
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
888 function handle_token_grant(event)
5223
8b2a36847912 mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents: 5222
diff changeset
889 local credentials = get_request_credentials(event.request);
8b2a36847912 mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents: 5222
diff changeset
890
3934
469408682152 mod_http_oauth2: Set content type on successful repsponses (fixes #1501)
Kim Alvefur <zash@zash.se>
parents: 3920
diff changeset
891 event.response.headers.content_type = "application/json";
5509
ae007be8a6bd mod_http_oauth2: Add Cache-Control and Pragma headers per by RFC 6749
Kim Alvefur <zash@zash.se>
parents: 5502
diff changeset
892 event.response.headers.cache_control = "no-store";
ae007be8a6bd mod_http_oauth2: Add Cache-Control and Pragma headers per by RFC 6749
Kim Alvefur <zash@zash.se>
parents: 5502
diff changeset
893 event.response.headers.pragma = "no-cache";
5513
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
894 local params = strict_formdecode(event.request.body);
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
895 if not params then
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
896 return oauth_error("invalid_request", "Could not parse request body as 'application/x-www-form-urlencoded'");
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
897 end
5223
8b2a36847912 mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents: 5222
diff changeset
898
5225
3439eb37f23b mod_http_oauth2: token endpoint: handle missing credentials
Matthew Wild <mwild1@gmail.com>
parents: 5224
diff changeset
899 if credentials and credentials.type == "basic" then
5385
544b92750a2a mod_http_oauth2: Advertise supported token endpoint auth methods
Kim Alvefur <zash@zash.se>
parents: 5384
diff changeset
900 -- client_secret_basic converted internally to client_secret_post
5223
8b2a36847912 mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents: 5222
diff changeset
901 params.client_id = http.urldecode(credentials.username);
8b2a36847912 mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents: 5222
diff changeset
902 params.client_secret = http.urldecode(credentials.password);
8b2a36847912 mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents: 5222
diff changeset
903 end
8b2a36847912 mod_http_oauth2: Support HTTP Basic auth on token endpoint
Matthew Wild <mwild1@gmail.com>
parents: 5222
diff changeset
904
6269
2505542c6c50 mod_http_oauth2: Deduplicate client authentication
Kim Alvefur <zash@zash.se>
parents: 6240
diff changeset
905 if not params.client_id then return oauth_error("invalid_request", "missing 'client_id'"); end
2505542c6c50 mod_http_oauth2: Deduplicate client authentication
Kim Alvefur <zash@zash.se>
parents: 6240
diff changeset
906 if not params.client_secret then return oauth_error("invalid_request", "missing 'client_secret'"); end
2505542c6c50 mod_http_oauth2: Deduplicate client authentication
Kim Alvefur <zash@zash.se>
parents: 6240
diff changeset
907
2505542c6c50 mod_http_oauth2: Deduplicate client authentication
Kim Alvefur <zash@zash.se>
parents: 6240
diff changeset
908 local client = check_client(params.client_id);
2505542c6c50 mod_http_oauth2: Deduplicate client authentication
Kim Alvefur <zash@zash.se>
parents: 6240
diff changeset
909 if not client then
2505542c6c50 mod_http_oauth2: Deduplicate client authentication
Kim Alvefur <zash@zash.se>
parents: 6240
diff changeset
910 return oauth_error("invalid_client", "incorrect credentials");
2505542c6c50 mod_http_oauth2: Deduplicate client authentication
Kim Alvefur <zash@zash.se>
parents: 6240
diff changeset
911 end
2505542c6c50 mod_http_oauth2: Deduplicate client authentication
Kim Alvefur <zash@zash.se>
parents: 6240
diff changeset
912
2505542c6c50 mod_http_oauth2: Deduplicate client authentication
Kim Alvefur <zash@zash.se>
parents: 6240
diff changeset
913 if not verify_client_secret(params.client_id, params.client_secret) then
2505542c6c50 mod_http_oauth2: Deduplicate client authentication
Kim Alvefur <zash@zash.se>
parents: 6240
diff changeset
914 module:log("debug", "client_secret mismatch");
2505542c6c50 mod_http_oauth2: Deduplicate client authentication
Kim Alvefur <zash@zash.se>
parents: 6240
diff changeset
915 return oauth_error("invalid_client", "incorrect credentials");
2505542c6c50 mod_http_oauth2: Deduplicate client authentication
Kim Alvefur <zash@zash.se>
parents: 6240
diff changeset
916 end
2505542c6c50 mod_http_oauth2: Deduplicate client authentication
Kim Alvefur <zash@zash.se>
parents: 6240
diff changeset
917
2505542c6c50 mod_http_oauth2: Deduplicate client authentication
Kim Alvefur <zash@zash.se>
parents: 6240
diff changeset
918
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
919 local grant_type = params.grant_type
6322
dfc035ecabb4 mod_http_oauth2: Remove defaults that should be included on clients
Kim Alvefur <zash@zash.se>
parents: 6321
diff changeset
920 if not array_contains(client.grant_types, grant_type) then
6282
7b3316ac24b3 mod_http_oauth2: Refactor client grant and response type checks
Kim Alvefur <zash@zash.se>
parents: 6281
diff changeset
921 return oauth_error("invalid_request", "'grant_type' not registered");
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
922 end
6281
9d88c3d9eea5 mod_http_oauth2: Enforce the registered grant types
Kim Alvefur <zash@zash.se>
parents: 6271
diff changeset
923
6282
7b3316ac24b3 mod_http_oauth2: Refactor client grant and response type checks
Kim Alvefur <zash@zash.se>
parents: 6281
diff changeset
924 local grant_handler = grant_type_handlers[grant_type];
7b3316ac24b3 mod_http_oauth2: Refactor client grant and response type checks
Kim Alvefur <zash@zash.se>
parents: 6281
diff changeset
925 if not grant_handler then
7b3316ac24b3 mod_http_oauth2: Refactor client grant and response type checks
Kim Alvefur <zash@zash.se>
parents: 6281
diff changeset
926 return oauth_error("invalid_request", "'grant_type' not available");
6281
9d88c3d9eea5 mod_http_oauth2: Enforce the registered grant types
Kim Alvefur <zash@zash.se>
parents: 6271
diff changeset
927 end
9d88c3d9eea5 mod_http_oauth2: Enforce the registered grant types
Kim Alvefur <zash@zash.se>
parents: 6271
diff changeset
928
6269
2505542c6c50 mod_http_oauth2: Deduplicate client authentication
Kim Alvefur <zash@zash.se>
parents: 6240
diff changeset
929 return grant_handler(params, client);
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
930 end
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
931
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
932 local function handle_authorization_request(event)
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
933 local request = event.request;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
934
5472
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
935 -- Directly returning errors to the user before we have a validated client object
4258
cc712899becd mod_http_oauth2: Unpack event object to improve readability
Kim Alvefur <zash@zash.se>
parents: 4257
diff changeset
936 if not request.url.query then
5472
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
937 return render_error(oauth_error("invalid_request", "Missing query parameters"));
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
938 end
5513
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
939 local params = strict_formdecode(request.url.query);
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
940 if not params then
5472
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
941 return render_error(oauth_error("invalid_request", "Invalid query parameters"));
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
942 end
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
943
5471
d4d333cb75b2 mod_http_oauth2: Clarify some error messages
Kim Alvefur <zash@zash.se>
parents: 5470
diff changeset
944 if not params.client_id then
5472
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
945 return render_error(oauth_error("invalid_request", "Missing 'client_id' parameter"));
5471
d4d333cb75b2 mod_http_oauth2: Clarify some error messages
Kim Alvefur <zash@zash.se>
parents: 5470
diff changeset
946 end
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
947
5510
a49d73e4262e mod_http_oauth2: Add client verification wrapper function
Kim Alvefur <zash@zash.se>
parents: 5509
diff changeset
948 local client = check_client(params.client_id);
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
949
5510
a49d73e4262e mod_http_oauth2: Add client verification wrapper function
Kim Alvefur <zash@zash.se>
parents: 5509
diff changeset
950 if not client then
5472
b80b6947b079 mod_http_oauth2: Always show early errors to user
Kim Alvefur <zash@zash.se>
parents: 5471
diff changeset
951 return render_error(oauth_error("invalid_request", "Invalid 'client_id' parameter"));
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
952 end
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
953
5477
5986e0edd7a3 mod_http_oauth2: Use validated redirect URI when returning errors to client
Kim Alvefur <zash@zash.se>
parents: 5476
diff changeset
954 local redirect_uri = get_redirect_uri(client, params.redirect_uri);
5986e0edd7a3 mod_http_oauth2: Use validated redirect URI when returning errors to client
Kim Alvefur <zash@zash.se>
parents: 5476
diff changeset
955 if not redirect_uri then
5475
022733437fef mod_http_oauth2: Validate redirect_uri before using it for error redirects
Kim Alvefur <zash@zash.se>
parents: 5474
diff changeset
956 return render_error(oauth_error("invalid_request", "Invalid 'redirect_uri' parameter"));
022733437fef mod_http_oauth2: Validate redirect_uri before using it for error redirects
Kim Alvefur <zash@zash.se>
parents: 5474
diff changeset
957 end
022733437fef mod_http_oauth2: Validate redirect_uri before using it for error redirects
Kim Alvefur <zash@zash.se>
parents: 5474
diff changeset
958 -- From this point we know that redirect_uri is safe to use
022733437fef mod_http_oauth2: Validate redirect_uri before using it for error redirects
Kim Alvefur <zash@zash.se>
parents: 5474
diff changeset
959
6282
7b3316ac24b3 mod_http_oauth2: Refactor client grant and response type checks
Kim Alvefur <zash@zash.se>
parents: 6281
diff changeset
960 local response_type = params.response_type;
6322
dfc035ecabb4 mod_http_oauth2: Remove defaults that should be included on clients
Kim Alvefur <zash@zash.se>
parents: 6321
diff changeset
961 if not array_contains(client.response_types, response_type) then
6282
7b3316ac24b3 mod_http_oauth2: Refactor client grant and response type checks
Kim Alvefur <zash@zash.se>
parents: 6281
diff changeset
962 return error_response(request, redirect_uri, oauth_error("invalid_client", "'response_type' not registered"));
7b3316ac24b3 mod_http_oauth2: Refactor client grant and response type checks
Kim Alvefur <zash@zash.se>
parents: 6281
diff changeset
963 end
7b3316ac24b3 mod_http_oauth2: Refactor client grant and response type checks
Kim Alvefur <zash@zash.se>
parents: 6281
diff changeset
964 if not allowed_response_type_handlers:contains(response_type) then
7b3316ac24b3 mod_http_oauth2: Refactor client grant and response type checks
Kim Alvefur <zash@zash.se>
parents: 6281
diff changeset
965 return error_response(request, redirect_uri, oauth_error("unsupported_response_type", "'response_type' not allowed"));
7b3316ac24b3 mod_http_oauth2: Refactor client grant and response type checks
Kim Alvefur <zash@zash.se>
parents: 6281
diff changeset
966 end
7b3316ac24b3 mod_http_oauth2: Refactor client grant and response type checks
Kim Alvefur <zash@zash.se>
parents: 6281
diff changeset
967 local response_handler = response_type_handlers[response_type];
7b3316ac24b3 mod_http_oauth2: Refactor client grant and response type checks
Kim Alvefur <zash@zash.se>
parents: 6281
diff changeset
968 if not response_handler then
7b3316ac24b3 mod_http_oauth2: Refactor client grant and response type checks
Kim Alvefur <zash@zash.se>
parents: 6281
diff changeset
969 return error_response(request, redirect_uri, oauth_error("unsupported_response_type"));
5405
c7a5caad28ef mod_http_oauth2: Enforce response type encoded in client_id
Kim Alvefur <zash@zash.se>
parents: 5404
diff changeset
970 end
c7a5caad28ef mod_http_oauth2: Enforce response type encoded in client_id
Kim Alvefur <zash@zash.se>
parents: 5404
diff changeset
971
5447
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
972 local requested_scopes = parse_scopes(params.scope or "");
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
973 if client.scope then
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
974 local client_scopes = set.new(parse_scopes(client.scope));
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
975 requested_scopes:filter(function(scope)
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
976 return client_scopes:contains(scope);
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
977 end);
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
978 end
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
979
5518
d87d0e4a8516 mod_http_oauth2: Validate the OpenID 'prompt' parameter
Kim Alvefur <zash@zash.se>
parents: 5514
diff changeset
980 -- The 'prompt' parameter from OpenID Core
5738
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
981 local prompt = set.new(parse_scopes(respect_prompt and params.prompt or "select_account login consent"));
5518
d87d0e4a8516 mod_http_oauth2: Validate the OpenID 'prompt' parameter
Kim Alvefur <zash@zash.se>
parents: 5514
diff changeset
982
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
983 local auth_state = get_auth_state(request);
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
984 if not auth_state.user then
5738
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
985 if not prompt:contains("login") then
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
986 -- Currently no cookies or such are used, so login is required every time.
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
987 return error_response(request, redirect_uri, oauth_error("login_required"));
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
988 end
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
989
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
990 -- Render login page
5466
398d936e77fb mod_http_oauth2: Add support for the OpenID 'login_hint' parameter
Kim Alvefur <zash@zash.se>
parents: 5465
diff changeset
991 local extra = {};
398d936e77fb mod_http_oauth2: Add support for the OpenID 'login_hint' parameter
Kim Alvefur <zash@zash.se>
parents: 5465
diff changeset
992 if params.login_hint then
5787
87920d436cb4 mod_http_oauth2: Handle login_hint without @hostpart
Kim Alvefur <zash@zash.se>
parents: 5775
diff changeset
993 extra.username_hint = (jid.prepped_split(params.login_hint) or encodings.stringprep.nodeprep(params.login_hint));
5738
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
994 elseif not prompt:contains("select_account") then
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
995 -- TODO If the login page is split into account selection followed by login
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
996 -- (e.g. password), and then the account selection could be skipped iff the
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
997 -- 'login_hint' parameter is present.
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
998 return error_response(request, redirect_uri, oauth_error("account_selection_required"));
5466
398d936e77fb mod_http_oauth2: Add support for the OpenID 'login_hint' parameter
Kim Alvefur <zash@zash.se>
parents: 5465
diff changeset
999 end
398d936e77fb mod_http_oauth2: Add support for the OpenID 'login_hint' parameter
Kim Alvefur <zash@zash.se>
parents: 5465
diff changeset
1000 return render_page(templates.login, { state = auth_state; client = client; extra = extra });
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1001 elseif auth_state.consent == nil then
5447
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
1002 local scopes, roles = split_scopes(requested_scopes);
5452
b071d8ee6555 mod_http_oauth2: Show only roles the user can use in consent dialog
Kim Alvefur <zash@zash.se>
parents: 5451
diff changeset
1003 roles = user_assumable_roles(auth_state.user.username, roles);
5738
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1004
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1005 if not prompt:contains("consent") then
6317
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
1006 if array_contains(scopes, "offline_access") then
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
1007 -- MUST ensure that the prompt parameter contains consent
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
1008 return error_response(request, redirect_uri, oauth_error("consent_required"));
8108aec64fb9 mod_http_oauth2: Support the "offline_access" for granting refresh tokens
Kim Alvefur <zash@zash.se>
parents: 6308
diff changeset
1009 end
5738
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1010 local grants = tokens.get_user_grants(auth_state.user.username);
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1011 local matching_grant;
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1012 if grants then
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1013 for grant_id, grant in pairs(grants) do
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1014 if grant.data and grant.data.oauth2_client and grant.data.oauth2_client.hash == client.client_hash then
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1015 if set.new(parse_scopes(grant.data.oauth2_scopes)) == set.new(scopes+roles) then
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1016 matching_grant = grant_id;
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1017 break
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1018 end
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1019 end
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1020 end
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1021 end
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1022
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1023 if not matching_grant then
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1024 return error_response(request, redirect_uri, oauth_error("consent_required"));
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1025 else
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1026 -- Consent for these scopes already granted to this exact client, continue
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1027 auth_state.scopes = scopes + roles;
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1028 auth_state.consent = "granted";
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1029 end
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1030
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1031 else
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1032 -- Render consent page
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1033 return render_page(templates.consent, { state = auth_state; client = client; scopes = scopes+roles }, true);
8488ebde5739 mod_http_oauth2: Skip consent screen if requested by client and same scopes already granted
Kim Alvefur <zash@zash.se>
parents: 5705
diff changeset
1034 end
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1035 elseif not auth_state.consent then
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1036 -- Notify client of rejection
5477
5986e0edd7a3 mod_http_oauth2: Use validated redirect URI when returning errors to client
Kim Alvefur <zash@zash.se>
parents: 5476
diff changeset
1037 return error_response(request, redirect_uri, oauth_error("access_denied"));
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1038 end
5271
3a1df3adad0c mod_http_oauth2: Allow user to decide which requested scopes to grant
Kim Alvefur <zash@zash.se>
parents: 5268
diff changeset
1039 -- else auth_state.consent == true
3a1df3adad0c mod_http_oauth2: Allow user to decide which requested scopes to grant
Kim Alvefur <zash@zash.se>
parents: 5268
diff changeset
1040
5447
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
1041 local granted_scopes = auth_state.scopes
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
1042 if client.scope then
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
1043 local client_scopes = set.new(parse_scopes(client.scope));
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
1044 granted_scopes:filter(function(scope)
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
1045 return client_scopes:contains(scope);
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
1046 end);
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
1047 end
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
1048
aa4828f040c5 mod_http_oauth2: Enforce client scope restrictions in authorization
Kim Alvefur <zash@zash.se>
parents: 5446
diff changeset
1049 params.scope = granted_scopes:concat(" ");
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1050
5257
b2120fb4a279 mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents: 5256
diff changeset
1051 local user_jid = jid.join(auth_state.user.username, module.host);
5262
e73f364b5624 mod_http_oauth2: Rename oauth client credential related functions
Kim Alvefur <zash@zash.se>
parents: 5259
diff changeset
1052 local client_secret = make_client_secret(params.client_id);
5257
b2120fb4a279 mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents: 5256
diff changeset
1053 local id_token_signer = jwt.new_signer("HS256", client_secret);
b2120fb4a279 mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents: 5256
diff changeset
1054 local id_token = id_token_signer({
b2120fb4a279 mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents: 5256
diff changeset
1055 iss = get_issuer();
b2120fb4a279 mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents: 5256
diff changeset
1056 sub = url.build({ scheme = "xmpp"; path = user_jid });
b2120fb4a279 mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents: 5256
diff changeset
1057 aud = params.client_id;
5853
b109773ce6fe mod_http_oauth2: Reuse JWT issuance time as substitute for auth time
Kim Alvefur <zash@zash.se>
parents: 5822
diff changeset
1058 auth_time = auth_state.user.iat;
5257
b2120fb4a279 mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents: 5256
diff changeset
1059 nonce = params.nonce;
6292
28fd42866be9 mod_http_oauth2: Add comment referencing RFC 8176
Kim Alvefur <zash@zash.se>
parents: 6291
diff changeset
1060 amr = auth_state.user.amr; -- RFC 8176: Authentication Method Reference Values
5257
b2120fb4a279 mod_http_oauth2: Implement and return ID Token in authorization code flow
Kim Alvefur <zash@zash.se>
parents: 5256
diff changeset
1061 });
5468
14b5446e22e1 mod_http_oauth2: Fix returning errors from response handlers
Kim Alvefur <zash@zash.se>
parents: 5467
diff changeset
1062 local ret = response_handler(client, params, user_jid, id_token);
14b5446e22e1 mod_http_oauth2: Fix returning errors from response handlers
Kim Alvefur <zash@zash.se>
parents: 5467
diff changeset
1063 if errors.is_err(ret) then
5477
5986e0edd7a3 mod_http_oauth2: Use validated redirect URI when returning errors to client
Kim Alvefur <zash@zash.se>
parents: 5476
diff changeset
1064 return error_response(request, redirect_uri, ret);
5468
14b5446e22e1 mod_http_oauth2: Fix returning errors from response handlers
Kim Alvefur <zash@zash.se>
parents: 5467
diff changeset
1065 end
14b5446e22e1 mod_http_oauth2: Fix returning errors from response handlers
Kim Alvefur <zash@zash.se>
parents: 5467
diff changeset
1066 return ret;
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
1067 end
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
1068
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1069 local function handle_device_authorization_request(event)
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1070 local request = event.request;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1071
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1072 local credentials = get_request_credentials(request);
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1073
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1074 local params = strict_formdecode(request.body);
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1075 if not params then
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1076 return render_error(oauth_error("invalid_request", "Invalid query parameters"));
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1077 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1078
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1079 if credentials and credentials.type == "basic" then
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1080 -- client_secret_basic converted internally to client_secret_post
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1081 params.client_id = http.urldecode(credentials.username);
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1082 local client_secret = http.urldecode(credentials.password);
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1083
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1084 if not verify_client_secret(params.client_id, client_secret) then
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1085 module:log("debug", "client_secret mismatch");
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1086 return oauth_error("invalid_client", "incorrect credentials");
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1087 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1088 else
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1089 return 401;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1090 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1091
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1092 local client = check_client(params.client_id);
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1093
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1094 if not client then
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1095 return render_error(oauth_error("invalid_request", "Invalid 'client_id' parameter"));
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1096 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1097
6318
fe797da37174 mod_http_oauth2: Use cheaper array member check
Kim Alvefur <zash@zash.se>
parents: 6317
diff changeset
1098 if not array_contains(client.grant_types, device_uri) then
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1099 return render_error(oauth_error("invalid_client", "Client not registered for device authorization grant"));
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1100 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1101
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1102 local requested_scopes = parse_scopes(params.scope or "");
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1103 if client.scope then
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1104 local client_scopes = set.new(parse_scopes(client.scope));
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1105 requested_scopes:filter(function(scope)
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1106 return client_scopes:contains(scope);
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1107 end);
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1108 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1109
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1110 -- TODO better code generator, this one should be easy to type from a
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1111 -- screen onto a phone
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1112 local user_code = (id.tiny() .. "-" .. id.tiny()):upper();
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1113 local collisions = 0;
5614
ad9b8f659c96 mod_http_oauth2: Namespace the various codes to minimize confusion
Kim Alvefur <zash@zash.se>
parents: 5612
diff changeset
1114 while codes:get("authorization_code:" .. device_uri .. "#" .. user_code) do
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1115 collisions = collisions + 1;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1116 if collisions > 10 then
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1117 return oauth_error("temporarily_unavailable");
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1118 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1119 user_code = (id.tiny() .. "-" .. id.tiny()):upper();
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1120 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1121 -- device code should be derivable after consent but not guessable by the user
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1122 local device_code = b64url(hashes.hmac_sha256(verification_key, user_code));
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1123 local verification_uri = module:http_url() .. "/device";
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1124 local verification_uri_complete = verification_uri .. "?" .. http.formencode({ user_code = user_code });
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1125
5647
ef0a283507c9 mod_http_oauth2: Make storage of various code more consistent
Kim Alvefur <zash@zash.se>
parents: 5646
diff changeset
1126 local expires = os.time() + 600;
ef0a283507c9 mod_http_oauth2: Make storage of various code more consistent
Kim Alvefur <zash@zash.se>
parents: 5646
diff changeset
1127 local dc_ok = codes:set("device_code:" .. params.client_id .. "#" .. device_code, { expires = expires });
5614
ad9b8f659c96 mod_http_oauth2: Namespace the various codes to minimize confusion
Kim Alvefur <zash@zash.se>
parents: 5612
diff changeset
1128 local uc_ok = codes:set("user_code:" .. user_code,
5647
ef0a283507c9 mod_http_oauth2: Make storage of various code more consistent
Kim Alvefur <zash@zash.se>
parents: 5646
diff changeset
1129 { user_code = user_code; expires = expires; client_id = params.client_id;
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1130 scope = requested_scopes:concat(" ") });
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1131 if not dc_ok or not uc_ok then
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1132 return oauth_error("temporarily_unavailable");
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1133 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1134
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1135 return {
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1136 headers = { content_type = "application/json"; cache_control = "no-store"; pragma = "no-cache" };
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1137 body = json.encode {
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1138 device_code = device_code;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1139 user_code = user_code;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1140 verification_uri = verification_uri;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1141 verification_uri_complete = verification_uri_complete;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1142 expires_in = 600;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1143 interval = 5;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1144 };
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1145 }
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1146 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1147
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1148 local function handle_device_verification_request(event)
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1149 local request = event.request;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1150 local params = strict_formdecode(request.url.query);
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1151 if not params or not params.user_code then
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1152 return render_page(templates.device, { client = false });
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1153 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1154
5614
ad9b8f659c96 mod_http_oauth2: Namespace the various codes to minimize confusion
Kim Alvefur <zash@zash.se>
parents: 5612
diff changeset
1155 local device_info = codes:get("user_code:" .. params.user_code);
ad9b8f659c96 mod_http_oauth2: Namespace the various codes to minimize confusion
Kim Alvefur <zash@zash.se>
parents: 5612
diff changeset
1156 if not device_info or code_expired(device_info) or not codes:set("user_code:" .. params.user_code, nil) then
5615
1893ae742f66 mod_http_oauth2: Show errors on device flow user code entry page
Kim Alvefur <zash@zash.se>
parents: 5614
diff changeset
1157 return render_page(templates.device, {
1893ae742f66 mod_http_oauth2: Show errors on device flow user code entry page
Kim Alvefur <zash@zash.se>
parents: 5614
diff changeset
1158 client = false;
1893ae742f66 mod_http_oauth2: Show errors on device flow user code entry page
Kim Alvefur <zash@zash.se>
parents: 5614
diff changeset
1159 error = oauth_error("expired_token", "Incorrect or expired code");
1893ae742f66 mod_http_oauth2: Show errors on device flow user code entry page
Kim Alvefur <zash@zash.se>
parents: 5614
diff changeset
1160 });
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1161 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1162
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1163 return {
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1164 status_code = 303;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1165 headers = {
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1166 location = module:http_url() .. "/authorize" .. "?" .. http.formencode({
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1167 client_id = device_info.client_id;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1168 redirect_uri = device_uri;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1169 response_type = "code";
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1170 scope = device_info.scope;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1171 state = new_device_token({ user_code = params.user_code });
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1172 });
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1173 };
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1174 }
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1175 end
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1176
5703
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1177 local function handle_introspection_request(event)
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1178 local request = event.request;
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1179 local credentials = get_request_credentials(request);
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1180 if not credentials or credentials.type ~= "basic" then
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1181 event.response.headers.www_authenticate = string.format("Basic realm=%q", module.host.."/"..module.name);
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1182 return 401;
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1183 end
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1184 -- OAuth "client" credentials
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1185 if not verify_client_secret(credentials.username, credentials.password) then
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1186 return 401;
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1187 end
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1188
5704
8cb3da7df521 mod_http_oauth2: Restrict introspection to clients own tokens
Kim Alvefur <zash@zash.se>
parents: 5703
diff changeset
1189 local client = check_client(credentials.username);
8cb3da7df521 mod_http_oauth2: Restrict introspection to clients own tokens
Kim Alvefur <zash@zash.se>
parents: 5703
diff changeset
1190 if not client then
8cb3da7df521 mod_http_oauth2: Restrict introspection to clients own tokens
Kim Alvefur <zash@zash.se>
parents: 5703
diff changeset
1191 return 401;
8cb3da7df521 mod_http_oauth2: Restrict introspection to clients own tokens
Kim Alvefur <zash@zash.se>
parents: 5703
diff changeset
1192 end
8cb3da7df521 mod_http_oauth2: Restrict introspection to clients own tokens
Kim Alvefur <zash@zash.se>
parents: 5703
diff changeset
1193
5703
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1194 local form_data = http.formdecode(request.body or "=");
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1195 local token = form_data.token;
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1196 if not token then
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1197 return 400;
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1198 end
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1199
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1200 local token_info = tokens.get_token_info(form_data.token);
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1201 if not token_info then
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1202 return { headers = { content_type = "application/json" }; body = json.encode { active = false } };
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1203 end
5704
8cb3da7df521 mod_http_oauth2: Restrict introspection to clients own tokens
Kim Alvefur <zash@zash.se>
parents: 5703
diff changeset
1204 local token_client = token_info.grant.data.oauth2_client;
8cb3da7df521 mod_http_oauth2: Restrict introspection to clients own tokens
Kim Alvefur <zash@zash.se>
parents: 5703
diff changeset
1205 if not token_client or token_client.hash ~= client.client_hash then
8cb3da7df521 mod_http_oauth2: Restrict introspection to clients own tokens
Kim Alvefur <zash@zash.se>
parents: 5703
diff changeset
1206 return 403;
8cb3da7df521 mod_http_oauth2: Restrict introspection to clients own tokens
Kim Alvefur <zash@zash.se>
parents: 5703
diff changeset
1207 end
5703
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1208
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1209 return {
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1210 headers = { content_type = "application/json" };
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1211 body = json.encode {
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1212 active = true;
5882
761142ee0ff2 mod_http_oauth2: Reflect changes to defaults etc
Kim Alvefur <zash@zash.se>
parents: 5853
diff changeset
1213 client_id = credentials.username; -- Verified via client hash
5703
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1214 username = jid.node(token_info.jid);
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1215 scope = token_info.grant.data.oauth2_scopes;
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1216 token_type = purpose_map[token_info.purpose];
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1217 exp = token.expires;
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1218 iat = token.created;
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1219 sub = url.build({ scheme = "xmpp"; path = token_info.jid });
5704
8cb3da7df521 mod_http_oauth2: Restrict introspection to clients own tokens
Kim Alvefur <zash@zash.se>
parents: 5703
diff changeset
1220 aud = credentials.username;
5703
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1221 iss = get_issuer();
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1222 jti = token_info.id;
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1223 };
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1224 };
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1225 end
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1226
5705
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1227 -- RFC 7009 says that the authorization server should validate that only the client that a token was issued to should be able to revoke it. However
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1228 -- this would prevent someone who comes across a leaked token from doing the responsible thing and revoking it, so this is not enforced by default.
5644
a44af1b646f5 mod_http_oauth2: Optionally enforce authentication on revocation endpoint
Kim Alvefur <zash@zash.se>
parents: 5626
diff changeset
1229 local strict_auth_revoke = module:get_option_boolean("oauth2_require_auth_revoke", false);
a44af1b646f5 mod_http_oauth2: Optionally enforce authentication on revocation endpoint
Kim Alvefur <zash@zash.se>
parents: 5626
diff changeset
1230
4370
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
1231 local function handle_revocation_request(event)
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
1232 local request, response = event.request, event.response;
5509
ae007be8a6bd mod_http_oauth2: Add Cache-Control and Pragma headers per by RFC 6749
Kim Alvefur <zash@zash.se>
parents: 5502
diff changeset
1233 response.headers.cache_control = "no-store";
ae007be8a6bd mod_http_oauth2: Add Cache-Control and Pragma headers per by RFC 6749
Kim Alvefur <zash@zash.se>
parents: 5502
diff changeset
1234 response.headers.pragma = "no-cache";
5705
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1235 local credentials = get_request_credentials(request);
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1236 if credentials then
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1237 if credentials.type ~= "basic" then
5265
f845c218e52c mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents: 5264
diff changeset
1238 response.headers.www_authenticate = string.format("Basic realm=%q", module.host.."/"..module.name);
f845c218e52c mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents: 5264
diff changeset
1239 return 401;
f845c218e52c mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents: 5264
diff changeset
1240 end
f845c218e52c mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents: 5264
diff changeset
1241 -- OAuth "client" credentials
f845c218e52c mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents: 5264
diff changeset
1242 if not verify_client_secret(credentials.username, credentials.password) then
f845c218e52c mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents: 5264
diff changeset
1243 return 401;
f845c218e52c mod_http_oauth2: Allow revoking a token without OAuth client credentials
Kim Alvefur <zash@zash.se>
parents: 5264
diff changeset
1244 end
5644
a44af1b646f5 mod_http_oauth2: Optionally enforce authentication on revocation endpoint
Kim Alvefur <zash@zash.se>
parents: 5626
diff changeset
1245 -- TODO check that it's their token I guess?
a44af1b646f5 mod_http_oauth2: Optionally enforce authentication on revocation endpoint
Kim Alvefur <zash@zash.se>
parents: 5626
diff changeset
1246 elseif strict_auth_revoke then
a44af1b646f5 mod_http_oauth2: Optionally enforce authentication on revocation endpoint
Kim Alvefur <zash@zash.se>
parents: 5626
diff changeset
1247 -- Why require auth to revoke a leaked token?
a44af1b646f5 mod_http_oauth2: Optionally enforce authentication on revocation endpoint
Kim Alvefur <zash@zash.se>
parents: 5626
diff changeset
1248 response.headers.www_authenticate = string.format("Basic realm=%q", module.host.."/"..module.name);
a44af1b646f5 mod_http_oauth2: Optionally enforce authentication on revocation endpoint
Kim Alvefur <zash@zash.se>
parents: 5626
diff changeset
1249 return 401;
4370
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
1250 end
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
1251
5513
0005d4201030 mod_http_oauth2: Reject duplicate form-urlencoded parameters
Kim Alvefur <zash@zash.se>
parents: 5512
diff changeset
1252 local form_data = strict_formdecode(event.request.body);
4370
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
1253 if not form_data or not form_data.token then
5267
60e0bc35de33 mod_http_oauth2: Relax payload content type checking in revocation
Kim Alvefur <zash@zash.se>
parents: 5266
diff changeset
1254 response.headers.accept = "application/x-www-form-urlencoded";
60e0bc35de33 mod_http_oauth2: Relax payload content type checking in revocation
Kim Alvefur <zash@zash.se>
parents: 5266
diff changeset
1255 return 415;
4370
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
1256 end
5705
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1257
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1258 if credentials then
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1259 local client = check_client(credentials.username);
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1260 if not client then
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1261 return 401;
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1262 end
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1263 local token_info = tokens.get_token_info(form_data.token);
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1264 if not token_info then
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1265 return 404;
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1266 end
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1267 local token_client = token_info.grant.data.oauth2_client;
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1268 if not token_client or token_client.hash ~= client.client_hash then
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1269 return 403;
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1270 end
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1271 end
527c747711f3 mod_http_oauth2: Limit revocation to clients own tokens in strict mode
Kim Alvefur <zash@zash.se>
parents: 5704
diff changeset
1272
4370
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
1273 local ok, err = tokens.revoke_token(form_data.token);
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
1274 if not ok then
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
1275 module:log("warn", "Unable to revoke token: %s", tostring(err));
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
1276 return 500;
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
1277 end
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
1278 return 200;
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
1279 end
dee6b5098278 mod_http_oauth2: Add endpoint to revoke a key (RFC 7009 kinda)
Matthew Wild <mwild1@gmail.com>
parents: 4340
diff changeset
1280
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1281 local registration_schema = {
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1282 title = "OAuth 2.0 Dynamic Client Registration Protocol";
5820
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1283 description = "This endpoint allows dynamically registering an OAuth 2.0 client.";
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1284 type = "object";
5237
3354f943c1fa mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents: 5236
diff changeset
1285 required = {
3354f943c1fa mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents: 5236
diff changeset
1286 -- These are shown to users in the template
3354f943c1fa mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents: 5236
diff changeset
1287 "client_name";
3354f943c1fa mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents: 5236
diff changeset
1288 "client_uri";
3354f943c1fa mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents: 5236
diff changeset
1289 -- We need at least one redirect URI for things to work
3354f943c1fa mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents: 5236
diff changeset
1290 "redirect_uris";
3354f943c1fa mod_http_oauth2: Require URL to client informational page in registration
Kim Alvefur <zash@zash.se>
parents: 5236
diff changeset
1291 };
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1292 properties = {
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1293 redirect_uris = {
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1294 title = "List of Redirect URIs";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1295 type = "array";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1296 minItems = 1;
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1297 uniqueItems = true;
5820
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1298 items = {
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1299 title = "Redirect URI";
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1300 type = "string";
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1301 format = "uri";
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1302 examples = {
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1303 "https://app.example.com/redirect";
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1304 "http://localhost:8080/redirect";
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1305 "com.example.app:/redirect";
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1306 oob_uri;
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1307 device_uri;
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1308 };
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1309 };
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1310 };
5377
ca477408f90b mod_http_oauth2: Fix misplaced 'default' on wrong side of } in client registration schema
Kim Alvefur <zash@zash.se>
parents: 5375
diff changeset
1311 token_endpoint_auth_method = {
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1312 title = "Token Endpoint Authentication Method";
5820
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1313 description = "Authentication method the client intends to use. Recommended is `client_secret_basic`. \z
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1314 `none` is only allowed for use with the insecure Implicit flow.";
5377
ca477408f90b mod_http_oauth2: Fix misplaced 'default' on wrong side of } in client registration schema
Kim Alvefur <zash@zash.se>
parents: 5375
diff changeset
1315 type = "string";
ca477408f90b mod_http_oauth2: Fix misplaced 'default' on wrong side of } in client registration schema
Kim Alvefur <zash@zash.se>
parents: 5375
diff changeset
1316 enum = { "none"; "client_secret_post"; "client_secret_basic" };
ca477408f90b mod_http_oauth2: Fix misplaced 'default' on wrong side of } in client registration schema
Kim Alvefur <zash@zash.se>
parents: 5375
diff changeset
1317 default = "client_secret_basic";
ca477408f90b mod_http_oauth2: Fix misplaced 'default' on wrong side of } in client registration schema
Kim Alvefur <zash@zash.se>
parents: 5375
diff changeset
1318 };
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1319 grant_types = {
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1320 title = "Grant Types";
5820
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1321 description = "List of grant types the client intends to use.";
5236
ff8623e2f9d9 mod_http_oauth2: Reorder client metadata validation schema
Kim Alvefur <zash@zash.se>
parents: 5231
diff changeset
1322 type = "array";
5455
80a81e7f3c4e mod_http_oauth2: Require non-empty arrays in client registration
Kim Alvefur <zash@zash.se>
parents: 5454
diff changeset
1323 minItems = 1;
5456
9008aea491bf mod_http_oauth2: Reject duplicate list items in client registration
Kim Alvefur <zash@zash.se>
parents: 5455
diff changeset
1324 uniqueItems = true;
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1325 items = {
5236
ff8623e2f9d9 mod_http_oauth2: Reorder client metadata validation schema
Kim Alvefur <zash@zash.se>
parents: 5231
diff changeset
1326 type = "string";
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1327 enum = {
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1328 "authorization_code";
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1329 "implicit";
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1330 "password";
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1331 "client_credentials";
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1332 "refresh_token";
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1333 "urn:ietf:params:oauth:grant-type:jwt-bearer";
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1334 "urn:ietf:params:oauth:grant-type:saml2-bearer";
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1335 device_uri;
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1336 };
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1337 };
5366
db4c66a1d24b mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents: 5365
diff changeset
1338 default = { "authorization_code" };
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1339 };
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1340 application_type = {
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1341 title = "Application Type";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1342 description = "Determines which kinds of redirect URIs the client may register. \z
5820
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1343 The value `web` limits the client to `https://` URLs with the same hostname as \z
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1344 in `client_uri` while the value `native` allows either loopback URLs like \z
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1345 `http://localhost:8080/` or application specific URIs like `com.example.app:/redirect`.";
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1346 type = "string";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1347 enum = { "native"; "web" };
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1348 default = "web";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1349 };
5456
9008aea491bf mod_http_oauth2: Reject duplicate list items in client registration
Kim Alvefur <zash@zash.se>
parents: 5455
diff changeset
1350 response_types = {
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1351 title = "Response Types";
5456
9008aea491bf mod_http_oauth2: Reject duplicate list items in client registration
Kim Alvefur <zash@zash.se>
parents: 5455
diff changeset
1352 type = "array";
9008aea491bf mod_http_oauth2: Reject duplicate list items in client registration
Kim Alvefur <zash@zash.se>
parents: 5455
diff changeset
1353 uniqueItems = true;
9008aea491bf mod_http_oauth2: Reject duplicate list items in client registration
Kim Alvefur <zash@zash.se>
parents: 5455
diff changeset
1354 items = { type = "string"; enum = { "code"; "token" } };
9008aea491bf mod_http_oauth2: Reject duplicate list items in client registration
Kim Alvefur <zash@zash.se>
parents: 5455
diff changeset
1355 default = { "code" };
9008aea491bf mod_http_oauth2: Reject duplicate list items in client registration
Kim Alvefur <zash@zash.se>
parents: 5455
diff changeset
1356 };
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1357 client_name = {
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1358 title = "Client Name";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1359 description = "Human-readable name of the client, presented to the user in the consent dialog.";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1360 type = "string";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1361 };
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1362 client_uri = {
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1363 title = "Client URL";
5820
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1364 description = "Should be an link to a page with information about the client. \z
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1365 The hostname in this URL must be the same as in every other '_uri' property.";
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1366 type = "string";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1367 format = "uri";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1368 pattern = "^https:";
5820
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1369 examples = { "https://app.example.com/" };
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1370 };
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1371 logo_uri = {
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1372 title = "Logo URL";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1373 description = "URL to the clients logotype (not currently used).";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1374 type = "string";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1375 format = "uri";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1376 pattern = "^https:";
5820
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1377 examples = { "https://app.example.com/appicon.png" };
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1378 };
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1379 scope = {
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1380 title = "Scopes";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1381 description = "Space-separated list of scopes the client promises to restrict itself to.";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1382 type = "string";
5820
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1383 examples = { "openid xmpp" };
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1384 };
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1385 contacts = {
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1386 title = "Contact Addresses";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1387 description = "Addresses, typically email or URLs where the client developers can be contacted.";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1388 type = "array";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1389 minItems = 1;
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1390 items = { type = "string"; format = "email" };
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1391 };
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1392 tos_uri = {
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1393 title = "Terms of Service URL";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1394 description = "Link to Terms of Service for the client, presented to the user in the consent dialog. \z
5820
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1395 MUST be a `https://` URL with hostname matching that of `client_uri`.";
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1396 type = "string";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1397 format = "uri";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1398 pattern = "^https:";
5820
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1399 examples = { "https://app.example.com/tos.html" };
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1400 };
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1401 policy_uri = {
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1402 title = "Privacy Policy URL";
5820
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1403 description = "Link to a Privacy Policy for the client. MUST be a `https://` URL with hostname matching that of `client_uri`.";
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1404 type = "string";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1405 format = "uri";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1406 pattern = "^https:";
5820
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1407 examples = { "https://app.example.com/policy.pdf" };
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1408 };
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1409 software_id = {
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1410 title = "Software ID";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1411 description = "Unique identifier for the client software, common for all instances. Typically an UUID.";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1412 type = "string";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1413 format = "uuid";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1414 };
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1415 software_version = {
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1416 title = "Software Version";
5612
17aa3bac7f3a mod_http_oauth2: Improve a description in schema
Kim Alvefur <zash@zash.se>
parents: 5605
diff changeset
1417 description = "Version of the client software being registered. \z
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1418 E.g. to allow revoking all related tokens in the event of a security incident.";
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1419 type = "string";
5820
03477980f1a9 mod_http_oauth2: Improve registration schema documentation parts
Kim Alvefur <zash@zash.se>
parents: 5819
diff changeset
1420 examples = { "2.3.1" };
5605
b496ebc12aed mod_http_oauth2: Add titles and descriptions to registration schema
Kim Alvefur <zash@zash.se>
parents: 5596
diff changeset
1421 };
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1422 };
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1423 }
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1424
5554
90449babaa48 mod_http_oauth2: Make allowed locales configurable
Kim Alvefur <zash@zash.se>
parents: 5553
diff changeset
1425 -- Limit per-locale fields to allowed locales, partly to keep size of client_id
90449babaa48 mod_http_oauth2: Make allowed locales configurable
Kim Alvefur <zash@zash.se>
parents: 5553
diff changeset
1426 -- down, partly because we don't yet use them for anything.
90449babaa48 mod_http_oauth2: Make allowed locales configurable
Kim Alvefur <zash@zash.se>
parents: 5553
diff changeset
1427 -- Only relevant for user-visible strings and URIs.
90449babaa48 mod_http_oauth2: Make allowed locales configurable
Kim Alvefur <zash@zash.se>
parents: 5553
diff changeset
1428 if allowed_locales[1] then
90449babaa48 mod_http_oauth2: Make allowed locales configurable
Kim Alvefur <zash@zash.se>
parents: 5553
diff changeset
1429 local props = registration_schema.properties;
90449babaa48 mod_http_oauth2: Make allowed locales configurable
Kim Alvefur <zash@zash.se>
parents: 5553
diff changeset
1430 for _, locale in ipairs(allowed_locales) do
90449babaa48 mod_http_oauth2: Make allowed locales configurable
Kim Alvefur <zash@zash.se>
parents: 5553
diff changeset
1431 props["client_name#" .. locale] = props["client_name"];
90449babaa48 mod_http_oauth2: Make allowed locales configurable
Kim Alvefur <zash@zash.se>
parents: 5553
diff changeset
1432 props["client_uri#" .. locale] = props["client_uri"];
90449babaa48 mod_http_oauth2: Make allowed locales configurable
Kim Alvefur <zash@zash.se>
parents: 5553
diff changeset
1433 props["logo_uri#" .. locale] = props["logo_uri"];
90449babaa48 mod_http_oauth2: Make allowed locales configurable
Kim Alvefur <zash@zash.se>
parents: 5553
diff changeset
1434 props["tos_uri#" .. locale] = props["tos_uri"];
90449babaa48 mod_http_oauth2: Make allowed locales configurable
Kim Alvefur <zash@zash.se>
parents: 5553
diff changeset
1435 props["policy_uri#" .. locale] = props["policy_uri"];
90449babaa48 mod_http_oauth2: Make allowed locales configurable
Kim Alvefur <zash@zash.se>
parents: 5553
diff changeset
1436 end
90449babaa48 mod_http_oauth2: Make allowed locales configurable
Kim Alvefur <zash@zash.se>
parents: 5553
diff changeset
1437 end
90449babaa48 mod_http_oauth2: Make allowed locales configurable
Kim Alvefur <zash@zash.se>
parents: 5553
diff changeset
1438
5367
93d445b26063 mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents: 5366
diff changeset
1439 local function redirect_uri_allowed(redirect_uri, client_uri, app_type)
5984
97375a78d2b5 mod_http_oauth2: Reject URLs with 'userinfo' part (thanks mimi89999)
Kim Alvefur <zash@zash.se>
parents: 5963
diff changeset
1440 local uri = strict_url_parse(redirect_uri);
5790
a967bb4972c5 mod_http_oauth2: Reject unparsable URLs
Kim Alvefur <zash@zash.se>
parents: 5789
diff changeset
1441 if not uri then
a967bb4972c5 mod_http_oauth2: Reject unparsable URLs
Kim Alvefur <zash@zash.se>
parents: 5789
diff changeset
1442 return false;
a967bb4972c5 mod_http_oauth2: Reject unparsable URLs
Kim Alvefur <zash@zash.se>
parents: 5789
diff changeset
1443 end
5457
9156a4754466 mod_http_oauth2: Reject relative redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5456
diff changeset
1444 if not uri.scheme then
9156a4754466 mod_http_oauth2: Reject relative redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5456
diff changeset
1445 return false; -- no relative URLs
9156a4754466 mod_http_oauth2: Reject relative redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5456
diff changeset
1446 end
5367
93d445b26063 mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents: 5366
diff changeset
1447 if app_type == "native" then
5458
813fe4f76286 mod_http_oauth2: Do minimal validation of private-use URI schemes
Kim Alvefur <zash@zash.se>
parents: 5457
diff changeset
1448 return uri.scheme == "http" and loopbacks:contains(uri.host) or redirect_uri == oob_uri or uri.scheme:find(".", 1, true) ~= nil;
5367
93d445b26063 mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents: 5366
diff changeset
1449 elseif app_type == "web" then
93d445b26063 mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents: 5366
diff changeset
1450 return uri.scheme == "https" and uri.host == client_uri.host;
93d445b26063 mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents: 5366
diff changeset
1451 end
93d445b26063 mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents: 5366
diff changeset
1452 end
93d445b26063 mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents: 5366
diff changeset
1453
5259
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
1454 function create_client(client_metadata)
5789
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1455 local valid, validation_errors = schema.validate(registration_schema, client_metadata);
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1456 if not valid then
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1457 return nil, errors.new({
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1458 type = "modify";
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1459 condition = "bad-request";
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1460 code = 400;
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1461 text = "Failed schema validation.";
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1462 extra = {
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1463 oauth2_response = {
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1464 error = "invalid_request";
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1465 error_description = "Client registration data failed schema validation."; -- TODO Generate from validation_errors?
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1466 -- JSON Schema Output Format
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1467 -- https://json-schema.org/draft/2020-12/draft-bhutton-json-schema-01#name-basic
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1468 valid = false;
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1469 errors = validation_errors;
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1470 };
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1471 };
b8a2b3ebe792 mod_http_oauth2: Return validation output added in trunk rev 72d7830505f0
Kim Alvefur <zash@zash.se>
parents: 5787
diff changeset
1472 });
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1473 end
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1474
5984
97375a78d2b5 mod_http_oauth2: Reject URLs with 'userinfo' part (thanks mimi89999)
Kim Alvefur <zash@zash.se>
parents: 5963
diff changeset
1475 local client_uri = strict_url_parse(client_metadata.client_uri);
5986
5f8a306c8306 mod_http_oauth2: Require a stringprepped host part of URLs
Kim Alvefur <zash@zash.se>
parents: 5985
diff changeset
1476 if not client_uri or client_uri.scheme ~= "https" or not client_uri.host or loopbacks:contains(client_uri.host) then
5651
dd2079b3dec6 mod_http_oauth2: Allow omitting application type for native apps
Kim Alvefur <zash@zash.se>
parents: 5647
diff changeset
1477 return nil, oauth_error("invalid_client_metadata", "Missing, invalid or insecure client_uri");
dd2079b3dec6 mod_http_oauth2: Allow omitting application type for native apps
Kim Alvefur <zash@zash.se>
parents: 5647
diff changeset
1478 end
dd2079b3dec6 mod_http_oauth2: Allow omitting application type for native apps
Kim Alvefur <zash@zash.se>
parents: 5647
diff changeset
1479
dd2079b3dec6 mod_http_oauth2: Allow omitting application type for native apps
Kim Alvefur <zash@zash.se>
parents: 5647
diff changeset
1480 if not client_metadata.application_type and redirect_uri_allowed(client_metadata.redirect_uris[1], client_uri, "native") then
dd2079b3dec6 mod_http_oauth2: Allow omitting application type for native apps
Kim Alvefur <zash@zash.se>
parents: 5647
diff changeset
1481 client_metadata.application_type = "native";
dd2079b3dec6 mod_http_oauth2: Allow omitting application type for native apps
Kim Alvefur <zash@zash.se>
parents: 5647
diff changeset
1482 -- else defaults to "web"
dd2079b3dec6 mod_http_oauth2: Allow omitting application type for native apps
Kim Alvefur <zash@zash.se>
parents: 5647
diff changeset
1483 end
dd2079b3dec6 mod_http_oauth2: Allow omitting application type for native apps
Kim Alvefur <zash@zash.se>
parents: 5647
diff changeset
1484
5366
db4c66a1d24b mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents: 5365
diff changeset
1485 -- Fill in default values
db4c66a1d24b mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents: 5365
diff changeset
1486 for propname, propspec in pairs(registration_schema.properties) do
db4c66a1d24b mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents: 5365
diff changeset
1487 if client_metadata[propname] == nil and type(propspec) == "table" and propspec.default ~= nil then
db4c66a1d24b mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents: 5365
diff changeset
1488 client_metadata[propname] = propspec.default;
db4c66a1d24b mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents: 5365
diff changeset
1489 end
db4c66a1d24b mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents: 5365
diff changeset
1490 end
db4c66a1d24b mod_http_oauth2: Fill in some client metadata defaults
Kim Alvefur <zash@zash.se>
parents: 5365
diff changeset
1491
5559
d7fb8b266663 mod_http_oauth2: Strip unknown client metadata
Kim Alvefur <zash@zash.se>
parents: 5554
diff changeset
1492 -- MUST ignore any metadata that it does not understand
d7fb8b266663 mod_http_oauth2: Strip unknown client metadata
Kim Alvefur <zash@zash.se>
parents: 5554
diff changeset
1493 for propname in pairs(client_metadata) do
d7fb8b266663 mod_http_oauth2: Strip unknown client metadata
Kim Alvefur <zash@zash.se>
parents: 5554
diff changeset
1494 if not registration_schema.properties[propname] then
d7fb8b266663 mod_http_oauth2: Strip unknown client metadata
Kim Alvefur <zash@zash.se>
parents: 5554
diff changeset
1495 client_metadata[propname] = nil;
d7fb8b266663 mod_http_oauth2: Strip unknown client metadata
Kim Alvefur <zash@zash.se>
parents: 5554
diff changeset
1496 end
d7fb8b266663 mod_http_oauth2: Strip unknown client metadata
Kim Alvefur <zash@zash.se>
parents: 5554
diff changeset
1497 end
d7fb8b266663 mod_http_oauth2: Strip unknown client metadata
Kim Alvefur <zash@zash.se>
parents: 5554
diff changeset
1498
5239
8620a635106e mod_http_oauth2: Validate basic URI syntax of redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5237
diff changeset
1499 for _, redirect_uri in ipairs(client_metadata.redirect_uris) do
5367
93d445b26063 mod_http_oauth2: Validate redirect URI depending on application type
Kim Alvefur <zash@zash.se>
parents: 5366
diff changeset
1500 if not redirect_uri_allowed(redirect_uri, client_uri, client_metadata.application_type) then
5402
fbf3ede7541b mod_http_oauth2: More appropriate error conditions in client validation
Kim Alvefur <zash@zash.se>
parents: 5401
diff changeset
1501 return nil, oauth_error("invalid_redirect_uri", "Invalid, insecure or inappropriate redirect URI.");
5242
4746609a6656 mod_http_oauth2: Validate that informative URLs match the redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5241
diff changeset
1502 end
4746609a6656 mod_http_oauth2: Validate that informative URLs match the redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5241
diff changeset
1503 end
4746609a6656 mod_http_oauth2: Validate that informative URLs match the redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5241
diff changeset
1504
5244
fa7bd721a3f6 mod_http_oauth2: Fix validation of informative URIs
Kim Alvefur <zash@zash.se>
parents: 5243
diff changeset
1505 for field, prop_schema in pairs(registration_schema.properties) do
5246
fd0d25b42cd9 mod_http_oauth2: Validate all URIs against client_uri in client registration
Kim Alvefur <zash@zash.se>
parents: 5245
diff changeset
1506 if field ~= "client_uri" and prop_schema.format == "uri" and client_metadata[field] then
5403
c574aaaa4d57 mod_http_oauth2: Simplify validation of various URIs
Kim Alvefur <zash@zash.se>
parents: 5402
diff changeset
1507 if not redirect_uri_allowed(client_metadata[field], client_uri, "web") then
c574aaaa4d57 mod_http_oauth2: Simplify validation of various URIs
Kim Alvefur <zash@zash.se>
parents: 5402
diff changeset
1508 return nil, oauth_error("invalid_client_metadata", "Invalid, insecure or inappropriate informative URI");
5242
4746609a6656 mod_http_oauth2: Validate that informative URLs match the redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5241
diff changeset
1509 end
5239
8620a635106e mod_http_oauth2: Validate basic URI syntax of redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5237
diff changeset
1510 end
8620a635106e mod_http_oauth2: Validate basic URI syntax of redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5237
diff changeset
1511 end
8620a635106e mod_http_oauth2: Validate basic URI syntax of redirect URIs
Kim Alvefur <zash@zash.se>
parents: 5237
diff changeset
1512
5406
b86d80e21c60 mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents: 5405
diff changeset
1513 local grant_types = set.new(client_metadata.grant_types);
b86d80e21c60 mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents: 5405
diff changeset
1514 local response_types = set.new(client_metadata.response_types);
b86d80e21c60 mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents: 5405
diff changeset
1515
6287
5b269511ade7 mod_http_oauth2: Forbid inclusion of disabled grant and response types
Kim Alvefur <zash@zash.se>
parents: 6286
diff changeset
1516 if not (grant_types - allowed_grant_type_handlers):empty() then
5b269511ade7 mod_http_oauth2: Forbid inclusion of disabled grant and response types
Kim Alvefur <zash@zash.se>
parents: 6286
diff changeset
1517 return nil, oauth_error("invalid_client_metadata", "Disallowed 'grant_types' specified");
5b269511ade7 mod_http_oauth2: Forbid inclusion of disabled grant and response types
Kim Alvefur <zash@zash.se>
parents: 6286
diff changeset
1518 elseif not (response_types - allowed_response_type_handlers):empty() then
5b269511ade7 mod_http_oauth2: Forbid inclusion of disabled grant and response types
Kim Alvefur <zash@zash.se>
parents: 6286
diff changeset
1519 return nil, oauth_error("invalid_client_metadata", "Disallowed 'response_types' specified");
5b269511ade7 mod_http_oauth2: Forbid inclusion of disabled grant and response types
Kim Alvefur <zash@zash.se>
parents: 6286
diff changeset
1520 end
5b269511ade7 mod_http_oauth2: Forbid inclusion of disabled grant and response types
Kim Alvefur <zash@zash.se>
parents: 6286
diff changeset
1521
5406
b86d80e21c60 mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents: 5405
diff changeset
1522 if grant_types:contains("authorization_code") and not response_types:contains("code") then
b86d80e21c60 mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents: 5405
diff changeset
1523 return nil, oauth_error("invalid_client_metadata", "Inconsistency between 'grant_types' and 'response_types'");
b86d80e21c60 mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents: 5405
diff changeset
1524 elseif grant_types:contains("implicit") and not response_types:contains("token") then
b86d80e21c60 mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents: 5405
diff changeset
1525 return nil, oauth_error("invalid_client_metadata", "Inconsistency between 'grant_types' and 'response_types'");
b86d80e21c60 mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents: 5405
diff changeset
1526 end
b86d80e21c60 mod_http_oauth2: Validate consistency of response and grant types
Kim Alvefur <zash@zash.se>
parents: 5405
diff changeset
1527
5793
990c6adc4407 mod_http_oauth2: Move some code earlier
Kim Alvefur <zash@zash.se>
parents: 5790
diff changeset
1528 if client_metadata.token_endpoint_auth_method ~= "none" then
990c6adc4407 mod_http_oauth2: Move some code earlier
Kim Alvefur <zash@zash.se>
parents: 5790
diff changeset
1529 -- Ensure that each client_id JWT with a client_secret is unique.
990c6adc4407 mod_http_oauth2: Move some code earlier
Kim Alvefur <zash@zash.se>
parents: 5790
diff changeset
1530 -- A short ID along with the issued at timestamp should be sufficient to
990c6adc4407 mod_http_oauth2: Move some code earlier
Kim Alvefur <zash@zash.se>
parents: 5790
diff changeset
1531 -- rule out brute force attacks.
990c6adc4407 mod_http_oauth2: Move some code earlier
Kim Alvefur <zash@zash.se>
parents: 5790
diff changeset
1532 -- Not needed for public clients without a secret, but those are expected
990c6adc4407 mod_http_oauth2: Move some code earlier
Kim Alvefur <zash@zash.se>
parents: 5790
diff changeset
1533 -- to be uncommon since they can only do the insecure implicit flow.
990c6adc4407 mod_http_oauth2: Move some code earlier
Kim Alvefur <zash@zash.se>
parents: 5790
diff changeset
1534 client_metadata.nonce = id.short();
990c6adc4407 mod_http_oauth2: Move some code earlier
Kim Alvefur <zash@zash.se>
parents: 5790
diff changeset
1535 end
990c6adc4407 mod_http_oauth2: Move some code earlier
Kim Alvefur <zash@zash.se>
parents: 5790
diff changeset
1536
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1537 -- Do we want to keep everything?
5459
260a859be86a mod_http_oauth2: Rename variables to improve clarity
Kim Alvefur <zash@zash.se>
parents: 5458
diff changeset
1538 local client_id = sign_client(client_metadata);
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1539
5221
22483cfce3ce mod_http_oauth2: Reflect ALL attributes of the client registration
Matthew Wild <mwild1@gmail.com>
parents: 5219
diff changeset
1540 client_metadata.client_id = client_id;
22483cfce3ce mod_http_oauth2: Reflect ALL attributes of the client registration
Matthew Wild <mwild1@gmail.com>
parents: 5219
diff changeset
1541 client_metadata.client_id_issued_at = os.time();
22483cfce3ce mod_http_oauth2: Reflect ALL attributes of the client registration
Matthew Wild <mwild1@gmail.com>
parents: 5219
diff changeset
1542
5407
149634647b48 mod_http_oauth2: Don't issue client_secret when not using authentication
Kim Alvefur <zash@zash.se>
parents: 5406
diff changeset
1543 if client_metadata.token_endpoint_auth_method ~= "none" then
5793
990c6adc4407 mod_http_oauth2: Move some code earlier
Kim Alvefur <zash@zash.se>
parents: 5790
diff changeset
1544 local client_secret = make_client_secret(client_id);
5407
149634647b48 mod_http_oauth2: Don't issue client_secret when not using authentication
Kim Alvefur <zash@zash.se>
parents: 5406
diff changeset
1545 client_metadata.client_secret = client_secret;
149634647b48 mod_http_oauth2: Don't issue client_secret when not using authentication
Kim Alvefur <zash@zash.se>
parents: 5406
diff changeset
1546 client_metadata.client_secret_expires_at = 0;
149634647b48 mod_http_oauth2: Don't issue client_secret when not using authentication
Kim Alvefur <zash@zash.se>
parents: 5406
diff changeset
1547
149634647b48 mod_http_oauth2: Don't issue client_secret when not using authentication
Kim Alvefur <zash@zash.se>
parents: 5406
diff changeset
1548 if not registration_options.accept_expired then
149634647b48 mod_http_oauth2: Don't issue client_secret when not using authentication
Kim Alvefur <zash@zash.se>
parents: 5406
diff changeset
1549 client_metadata.client_secret_expires_at = client_metadata.client_id_issued_at + (registration_options.default_ttl or 3600);
149634647b48 mod_http_oauth2: Don't issue client_secret when not using authentication
Kim Alvefur <zash@zash.se>
parents: 5406
diff changeset
1550 end
5202
b81fd0d22c66 mod_http_oauth2: Calculate client secret expiry in registration response
Kim Alvefur <zash@zash.se>
parents: 5201
diff changeset
1551 end
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1552
5259
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
1553 return client_metadata;
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
1554 end
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
1555
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
1556 local function handle_register_request(event)
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
1557 local request = event.request;
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
1558 local client_metadata, err = json.decode(request.body);
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
1559 if err then
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
1560 return oauth_error("invalid_request", "Invalid JSON");
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
1561 end
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
1562
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
1563 local response, err = create_client(client_metadata);
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
1564 if err then return err end
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
1565
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1566 return {
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1567 status_code = 201;
5509
ae007be8a6bd mod_http_oauth2: Add Cache-Control and Pragma headers per by RFC 6749
Kim Alvefur <zash@zash.se>
parents: 5502
diff changeset
1568 headers = {
ae007be8a6bd mod_http_oauth2: Add Cache-Control and Pragma headers per by RFC 6749
Kim Alvefur <zash@zash.se>
parents: 5502
diff changeset
1569 cache_control = "no-store";
ae007be8a6bd mod_http_oauth2: Add Cache-Control and Pragma headers per by RFC 6749
Kim Alvefur <zash@zash.se>
parents: 5502
diff changeset
1570 pragma = "no-cache";
ae007be8a6bd mod_http_oauth2: Add Cache-Control and Pragma headers per by RFC 6749
Kim Alvefur <zash@zash.se>
parents: 5502
diff changeset
1571 content_type = "application/json";
ae007be8a6bd mod_http_oauth2: Add Cache-Control and Pragma headers per by RFC 6749
Kim Alvefur <zash@zash.se>
parents: 5502
diff changeset
1572 };
5259
8fba651b10ef mod_http_oauth2: Refactor to allow reuse of OAuth client creation
Kim Alvefur <zash@zash.se>
parents: 5258
diff changeset
1573 body = json.encode(response);
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1574 };
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1575 end
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1576
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1577 if not registration_key then
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1578 module:log("info", "No 'oauth2_registration_key', dynamic client registration disabled")
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1579 handle_authorization_request = nil
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1580 handle_register_request = nil
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1581 handle_device_authorization_request = nil
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1582 handle_device_verification_request = nil
5193
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1583 end
2bb29ece216b mod_http_oauth2: Implement stateless dynamic client registration
Kim Alvefur <zash@zash.se>
parents: 5192
diff changeset
1584
5228
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1585 local function handle_userinfo_request(event)
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1586 local request = event.request;
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1587 local credentials = get_request_credentials(request);
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1588 if not credentials or not credentials.bearer_token then
5336
77ac04bd2f65 mod_http_oauth2: Add some debug logging for UserInfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5335
diff changeset
1589 module:log("debug", "Missing credentials for UserInfo endpoint: %q", credentials)
5335
53c6f49dcbb8 mod_http_oauth2: Correct error code when missing credentials for userinfo
Kim Alvefur <zash@zash.se>
parents: 5280
diff changeset
1590 return 401;
5228
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1591 end
5336
77ac04bd2f65 mod_http_oauth2: Add some debug logging for UserInfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5335
diff changeset
1592 local token_info,err = tokens.get_token_info(credentials.bearer_token);
5228
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1593 if not token_info then
5336
77ac04bd2f65 mod_http_oauth2: Add some debug logging for UserInfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5335
diff changeset
1594 module:log("debug", "UserInfo query failed token validation: %s", err)
5228
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1595 return 403;
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1596 end
5337
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1597 local scopes = set.new()
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1598 if type(token_info.grant.data) == "table" and type(token_info.grant.data.oauth2_scopes) == "string" then
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1599 scopes:add_list(parse_scopes(token_info.grant.data.oauth2_scopes));
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1600 else
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1601 module:log("debug", "token_info = %q", token_info)
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1602 end
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1603
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1604 if not scopes:contains("openid") then
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1605 module:log("debug", "Missing the 'openid' scope in %q", scopes)
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1606 -- The 'openid' scope is required for access to this endpoint.
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1607 return 403;
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1608 end
5228
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1609
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1610 local user_info = {
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1611 iss = get_issuer();
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1612 sub = url.build({ scheme = "xmpp"; path = token_info.jid });
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1613 }
5337
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1614
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1615 local token_claims = set.intersection(openid_claims, scopes);
5375
8b7d97f0ae8a mod_http_oauth2: Fix to include "openid" scope in discovery metadata
Kim Alvefur <zash@zash.se>
parents: 5367
diff changeset
1616 token_claims:remove("openid"); -- that's "iss" and "sub" above
5337
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1617 if not token_claims:empty() then
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1618 -- Another module can do that
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1619 module:fire_event("token/userinfo", {
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1620 token = token_info;
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1621 claims = token_claims;
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1622 username = jid.split(token_info.jid);
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1623 userinfo = user_info;
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1624 });
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1625 end
8d8e85d6dc91 mod_http_oauth2: Support OpenID UserInfo claims
Kim Alvefur <zash@zash.se>
parents: 5336
diff changeset
1626
5228
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1627 return {
5258
9629971e307f mod_http_oauth2: Fix userinfo status code off-by-one
Kim Alvefur <zash@zash.se>
parents: 5257
diff changeset
1628 status_code = 200;
5228
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1629 headers = { content_type = "application/json" };
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1630 body = json.encode(user_info);
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1631 };
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1632 end
77cd01af06a9 mod_http_oauth2: Implement the OpenID userinfo endpoint
Kim Alvefur <zash@zash.se>
parents: 5225
diff changeset
1633
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1634 module:depends("http");
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1635 module:provides("http", {
5480
5108f63e762b mod_http_oauth2: Allow CORS for browser clients
Kim Alvefur <zash@zash.se>
parents: 5479
diff changeset
1636 cors = { enabled = true; credentials = true };
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1637 route = {
5382
12498c0d705f mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents: 5378
diff changeset
1638 -- OAuth 2.0 in 5 simple steps!
12498c0d705f mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents: 5378
diff changeset
1639 -- This is the normal 'authorization_code' flow.
12498c0d705f mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents: 5378
diff changeset
1640
12498c0d705f mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents: 5378
diff changeset
1641 -- Step 1. Create OAuth client
6207
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1642 ["GET /register"] = { headers = { content_type = "application/schema+json" }; body = json.encode(registration_schema) };
5382
12498c0d705f mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents: 5378
diff changeset
1643 ["POST /register"] = handle_register_request;
12498c0d705f mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents: 5378
diff changeset
1644
5596
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1645 -- Device flow
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1646 ["POST /device"] = handle_device_authorization_request;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1647 ["GET /device"] = handle_device_verification_request;
7040d0772758 mod_http_oauth2: Implement RFC 8628 Device Authorization Grant
Kim Alvefur <zash@zash.se>
parents: 5580
diff changeset
1648
5382
12498c0d705f mod_http_oauth2: Reorder routes into order they happen in OAuth 2.0
Kim Alvefur <zash@zash.se>
parents: 5378
diff changeset
1649 -- Step 2. User-facing login and consent view
4256
c4b9d4ba839b mod_http_oauth2: Authorization code flow
Kim Alvefur <zash@zash.se>
parents: 4237
diff changeset
1650 ["GET /authorize"] = handle_authorization_request;
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1651 ["POST /authorize"] = handle_authorization_request;
5548
fd3c12c40cd9 mod_http_oauth2: Disable CORS for authorization endpoint
Kim Alvefur <zash@zash.se>
parents: 5547
diff changeset
1652 ["OPTIONS /authorize"] = { status_code = 403; body = "" };
5245
e22cae58141d mod_http_oauth2: Organize HTTP routes with comments
Kim Alvefur <zash@zash.se>
parents: 5244
diff changeset
1653
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1654 -- Optional static content for templates
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1655 ["GET /style.css"] = templates.css and {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1656 headers = {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1657 ["Content-Type"] = "text/css";
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1658 };
5665
7c105277a9ca mod_http_oauth2: Remove broken in-CSS templating
Kim Alvefur <zash@zash.se>
parents: 5651
diff changeset
1659 body = templates.css;
5208
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1660 } or nil;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1661 ["GET /script.js"] = templates.js and {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1662 headers = {
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1663 ["Content-Type"] = "text/javascript";
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1664 };
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1665 body = templates.js;
aaa64c647e12 mod_http_oauth2: Add authentication, consent and error pages
Matthew Wild <mwild1@gmail.com>
parents: 5207
diff changeset
1666 } or nil;
5393
9b9d612f9083 mod_http_oauth2: Add way to retrieve registration schema
Kim Alvefur <zash@zash.se>
parents: 5392
diff changeset
1667
6207
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1668 -- Step 3. User is redirected to the 'redirect_uri' along with an
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1669 -- authorization code. In the insecure 'implicit' flow, the access token
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1670 -- is delivered here.
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1671
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1672 -- Step 4. Retrieve access token using the code.
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1673 ["POST /token"] = handle_token_grant;
5396
ac7c5669e5f5 mod_http_oauth2: Return status 405 for GET to endpoints without GET handler
Kim Alvefur <zash@zash.se>
parents: 5394
diff changeset
1674 ["GET /token"] = function() return 405; end;
6207
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1675
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1676 -- Step 4 is later repeated using the refresh token to get new access tokens.
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1677
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1678 -- Get info about a token
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1679 ["POST /introspect"] = handle_introspection_request;
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1680 ["GET /introspect"] = function() return 405; end;
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1681
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1682 -- Get info about the user, used for OpenID Connect
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1683 ["GET /userinfo"] = handle_userinfo_request;
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1684
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1685 -- Step 5. Revoke token (access or refresh)
a1a33f0f6f6e mod_http_oauth2: Reorder HTTP handler (noop)
Kim Alvefur <zash@zash.se>
parents: 6037
diff changeset
1686 ["POST /revoke"] = handle_revocation_request;
5396
ac7c5669e5f5 mod_http_oauth2: Return status 405 for GET to endpoints without GET handler
Kim Alvefur <zash@zash.se>
parents: 5394
diff changeset
1687 ["GET /revoke"] = function() return 405; end;
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1688 };
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1689 });
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1690
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1691 local http_server = require "net.http.server";
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1692
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1693 module:hook_object_event(http_server, "http-error", function (event)
4276
ec33b3b1136c mod_http_oauth2: Fix passing OAuth-specific error details
Kim Alvefur <zash@zash.se>
parents: 4272
diff changeset
1694 local oauth2_response = event.error and event.error.extra and event.error.extra.oauth2_response;
3903
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1695 if not oauth2_response then
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1696 return;
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1697 end
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1698 event.response.headers.content_type = "application/json";
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1699 event.response.status_code = event.error.code or 400;
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1700 return json.encode(oauth2_response);
cfeb93b80621 mod_http_oauth2: OAuth2 API (work in progress for developers only)
Matthew Wild <mwild1@gmail.com>
parents:
diff changeset
1701 end, 5);
5189
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1702
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1703 -- OIDC Discovery
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1704
5502
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1705 function get_authorization_server_metadata()
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1706 if authorization_server_metadata then
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1707 return authorization_server_metadata;
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1708 end
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1709 authorization_server_metadata = {
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1710 -- RFC 8414: OAuth 2.0 Authorization Server Metadata
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1711 issuer = get_issuer();
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1712 authorization_endpoint = handle_authorization_request and module:http_url() .. "/authorize" or nil;
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1713 token_endpoint = handle_token_grant and module:http_url() .. "/token" or nil;
6291
7cf1fcac9b94 mod_http_oauth2: Reorder metadata by source
Kim Alvefur <zash@zash.se>
parents: 6289
diff changeset
1714 jwks_uri = nil; -- REQUIRED in OpenID Discovery but not in OAuth 2.0 Metadata
5502
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1715 registration_endpoint = handle_register_request and module:http_url() .. "/register" or nil;
6319
63ef69b2f046 mod_http_oauth2: Assume Prosody 13.0+ roles are available
Kim Alvefur <zash@zash.se>
parents: 6318
diff changeset
1716 scopes_supported = array({ "xmpp" }):append(array(it.keys(usermanager.get_all_roles(module.host)))):append(array(openid_claims:items()));
5502
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1717 response_types_supported = array(it.keys(response_type_handlers));
6291
7cf1fcac9b94 mod_http_oauth2: Reorder metadata by source
Kim Alvefur <zash@zash.se>
parents: 6289
diff changeset
1718 response_modes_supported = array(it.keys(response_type_handlers)):map(tmap { token = "fragment"; code = "query" });
7cf1fcac9b94 mod_http_oauth2: Reorder metadata by source
Kim Alvefur <zash@zash.se>
parents: 6289
diff changeset
1719 grant_types_supported = array(it.keys(grant_type_handlers));
7cf1fcac9b94 mod_http_oauth2: Reorder metadata by source
Kim Alvefur <zash@zash.se>
parents: 6289
diff changeset
1720 token_endpoint_auth_methods_supported = array({ "client_secret_basic"; "client_secret_post"; "none" });
7cf1fcac9b94 mod_http_oauth2: Reorder metadata by source
Kim Alvefur <zash@zash.se>
parents: 6289
diff changeset
1721 token_endpoint_auth_signing_alg_values_supported = nil;
7cf1fcac9b94 mod_http_oauth2: Reorder metadata by source
Kim Alvefur <zash@zash.se>
parents: 6289
diff changeset
1722 service_documentation = module:get_option_string("oauth2_service_documentation", "https://modules.prosody.im/mod_http_oauth2.html");
7cf1fcac9b94 mod_http_oauth2: Reorder metadata by source
Kim Alvefur <zash@zash.se>
parents: 6289
diff changeset
1723 ui_locales_supported = allowed_locales[1] and allowed_locales;
5502
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1724 op_policy_uri = module:get_option_string("oauth2_policy_url", nil);
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1725 op_tos_uri = module:get_option_string("oauth2_terms_url", nil);
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1726 revocation_endpoint = handle_revocation_request and module:http_url() .. "/revoke" or nil;
6291
7cf1fcac9b94 mod_http_oauth2: Reorder metadata by source
Kim Alvefur <zash@zash.se>
parents: 6289
diff changeset
1727 revocation_endpoint_auth_methods_supported = array({ "client_secret_basic"; "client_secret_post"; "none" });
7cf1fcac9b94 mod_http_oauth2: Reorder metadata by source
Kim Alvefur <zash@zash.se>
parents: 6289
diff changeset
1728 revocation_endpoint_auth_signing_alg_values_supported = nil;
5703
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1729 introspection_endpoint = handle_introspection_request and module:http_url() .. "/introspect";
b43c989fb69c mod_http_oauth2: Implement introspection endpoint
Kim Alvefur <zash@zash.se>
parents: 5688
diff changeset
1730 introspection_endpoint_auth_methods_supported = nil;
6291
7cf1fcac9b94 mod_http_oauth2: Reorder metadata by source
Kim Alvefur <zash@zash.se>
parents: 6289
diff changeset
1731 introspection_endpoint_auth_signing_alg_values_supported = nil;
5502
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1732 code_challenge_methods_supported = array(it.keys(verifier_transforms));
6291
7cf1fcac9b94 mod_http_oauth2: Reorder metadata by source
Kim Alvefur <zash@zash.se>
parents: 6289
diff changeset
1733
7cf1fcac9b94 mod_http_oauth2: Reorder metadata by source
Kim Alvefur <zash@zash.se>
parents: 6289
diff changeset
1734 -- RFC 8628: OAuth 2.0 Device Authorization Grant
7cf1fcac9b94 mod_http_oauth2: Reorder metadata by source
Kim Alvefur <zash@zash.se>
parents: 6289
diff changeset
1735 device_authorization_endpoint = handle_device_authorization_request and module:http_url() .. "/device";
7cf1fcac9b94 mod_http_oauth2: Reorder metadata by source
Kim Alvefur <zash@zash.se>
parents: 6289
diff changeset
1736
7cf1fcac9b94 mod_http_oauth2: Reorder metadata by source
Kim Alvefur <zash@zash.se>
parents: 6289
diff changeset
1737 -- RFC 9207: OAuth 2.0 Authorization Server Issuer Identification
5502
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1738 authorization_response_iss_parameter_supported = true;
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1739
6291
7cf1fcac9b94 mod_http_oauth2: Reorder metadata by source
Kim Alvefur <zash@zash.se>
parents: 6289
diff changeset
1740 -- OpenID Connect Discovery 1.0
6037
277ccafb4826 mod_http_oauth2: Fix check for userinfo endpoint handler
Kim Alvefur <zash@zash.se>
parents: 5989
diff changeset
1741 userinfo_endpoint = handle_userinfo_request and module:http_url() .. "/userinfo" or nil;
5502
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1742 id_token_signing_alg_values_supported = { "HS256" }; -- The algorithm RS256 MUST be included, but we use HS256 and client_secret as shared key.
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1743 }
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1744 return authorization_server_metadata;
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1745 end
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1746
5189
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1747 module:provides("http", {
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1748 name = "oauth2-discovery";
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1749 default_path = "/.well-known/oauth-authorization-server";
5480
5108f63e762b mod_http_oauth2: Allow CORS for browser clients
Kim Alvefur <zash@zash.se>
parents: 5479
diff changeset
1750 cors = { enabled = true };
5189
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1751 route = {
5502
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1752 ["GET"] = function()
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1753 return {
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1754 headers = { content_type = "application/json" };
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1755 body = json.encode(get_authorization_server_metadata());
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1756 }
fd4d89a5b8db mod_http_oauth2: Add provisions for dynamically adding simple scopes
Kim Alvefur <zash@zash.se>
parents: 5501
diff changeset
1757 end
5189
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1758 };
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1759 });
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1760
4ee8eb1134a8 mod_http_oauth2: Add OIDC discovery endpoint (thanks Zash)
Matthew Wild <mwild1@gmail.com>
parents: 5188
diff changeset
1761 module:shared("tokenauth/oauthbearer_config").oidc_discovery_url = module:http_url("oauth2-discovery", "/.well-known/oauth-authorization-server");