# HG changeset patch # User Matthew Wild # Date 1582493813 0 # Node ID cfeb93b8062145aed5467673765a63c1bd115fed # Parent 341850e8866f542cc924660cb125660daf514a84 mod_http_oauth2: OAuth2 API (work in progress for developers only) diff -r 341850e8866f -r cfeb93b80621 mod_http_oauth2/README.markdown --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_http_oauth2/README.markdown Sun Feb 23 21:36:53 2020 +0000 @@ -0,0 +1,20 @@ +--- +labels: +- Stage-Alpha +summary: 'OAuth2 API' +... + +Introduction +============ + +This module is a work-in-progress intended for developers only! + +Configuration +============= + +None currently. + +Compatibility +============= + +Requires Prosody trunk. diff -r 341850e8866f -r cfeb93b80621 mod_http_oauth2/mod_http_oauth2.lua --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mod_http_oauth2/mod_http_oauth2.lua Sun Feb 23 21:36:53 2020 +0000 @@ -0,0 +1,76 @@ +module:set_global(); + +local http = require "util.http"; +local jid = require "util.jid"; +local json = require "util.json"; +local usermanager = require "core.usermanager"; +local errors = require "util.error"; + +local function oauth_error(err_name, err_desc) + return errors.new({ + type = "modify"; + condition = "bad-request"; + code = err_name == "invalid_client" and 401 or 400; + text = err_desc and (err_name..": "..err_desc) or err_name; + context = { oauth2_response = { error = err_name, error_description = err_desc } }; + }); +end + +local function new_access_token(username, host, scope, ttl) + return { + token_type = "bearer"; + access_token = "test-token"; + expires_in = ttl; + -- TODO: include refresh_token when implemented + }; +end + +local grant_type_handlers = {}; + +function grant_type_handlers.password(params) + local request_jid = assert(params.username, oauth_error("invalid_request", "missing 'username' (JID)")); + local request_password = assert(params.password, oauth_error("invalid_request", "missing 'password'")); + local request_username, request_host = jid.prepped_split(request_jid); + if params.scope then + return oauth_error("invalid_scope", "unknown scope requested"); + end + if not (request_username and request_host) or not (hosts[request_host]) then + return oauth_error("invalid_request", "invalid JID"); + end + if usermanager.test_password(request_username, request_host, request_password) then + return json.encode(new_access_token(request_username, request_host, nil, nil)); + end + return oauth_error("invalid_grant", "incorrect credentials"); +end + +function handle_token_grant(event) + local params = http.formdecode(event.request.body); + if not params then + return oauth_error("invalid_request"); + end + local grant_type = params.grant_type + local grant_handler = grant_type_handlers[grant_type]; + if not grant_handler then + return oauth_error("unsupported_grant_type"); + end + return grant_handler(params); +end + +module:depends("http"); +module:provides("http", { + route = { + ["POST /token"] = handle_token_grant; + }; +}); + +local http_server = require "net.http.server"; + +module:hook_object_event(http_server, "http-error", function (event) + local oauth2_response = event.error and event.error.context and event.error.context.oauth2_response; + if not oauth2_response then + return; + end + event.response.headers.content_type = "application/json"; + event.response.status_code = event.error.code or 400; + return json.encode(oauth2_response); +end, 5);