local M = {}
local function urlencode(s)
return (tostring(s):gsub("([^%w%-%.%_%~])", function(c)
return string.format("%%%02X", string.byte(c))
end))
end
function M.client(opts)
opts = opts or {}
local public_url = opts.public_url and opts.public_url:gsub("/+$", "") or nil
local admin_url = opts.admin_url and opts.admin_url:gsub("/+$", "") or nil
local function require_public()
if not public_url then
error("kratos: public_url not configured")
end
end
local function require_admin()
if not admin_url then
error("kratos: admin_url not configured")
end
end
local function public_get(path_str, cookie)
require_public()
local headers = {}
if cookie then headers["Cookie"] = cookie end
local resp = http.get(public_url .. path_str, { headers = headers })
if resp.status ~= 200 then
error("kratos: GET " .. path_str .. " HTTP " .. resp.status .. ": " .. resp.body)
end
return json.parse(resp.body)
end
local function public_post(path_str, payload, cookie)
require_public()
local headers = { ["Content-Type"] = "application/json" }
if cookie then headers["Cookie"] = cookie end
local resp = http.post(public_url .. path_str, payload, { headers = headers })
if resp.status ~= 200 and resp.status ~= 201 then
if resp.status == 422 then
return json.parse(resp.body)
end
error("kratos: POST " .. path_str .. " HTTP " .. resp.status .. ": " .. resp.body)
end
return json.parse(resp.body)
end
local function admin_get(path_str)
require_admin()
local resp = http.get(admin_url .. path_str)
if resp.status ~= 200 and resp.status ~= 404 then
error("kratos: GET " .. path_str .. " HTTP " .. resp.status .. ": " .. resp.body)
end
if resp.status == 404 then return nil end
return json.parse(resp.body)
end
local function admin_post(path_str, payload)
require_admin()
local resp = http.post(admin_url .. path_str, payload)
if resp.status ~= 200 and resp.status ~= 201 then
error("kratos: POST " .. path_str .. " HTTP " .. resp.status .. ": " .. resp.body)
end
return json.parse(resp.body)
end
local function admin_put(path_str, payload)
require_admin()
local resp = http.put(admin_url .. path_str, payload)
if resp.status ~= 200 then
error("kratos: PUT " .. path_str .. " HTTP " .. resp.status .. ": " .. resp.body)
end
return json.parse(resp.body)
end
local c = {}
c.sessions = {}
function c.sessions:whoami(cookie)
require_public()
local headers = {}
if cookie then headers["Cookie"] = cookie end
local resp = http.get(public_url .. "/sessions/whoami", { headers = headers })
if resp.status == 200 then
return json.parse(resp.body)
elseif resp.status == 401 then
return nil
end
error("kratos: whoami HTTP " .. resp.status .. ": " .. resp.body)
end
function c.sessions:list(identity_id)
return admin_get("/admin/identities/" .. urlencode(identity_id) .. "/sessions")
end
function c.sessions:revoke(identity_id)
require_admin()
local resp = http.delete(admin_url .. "/admin/identities/" .. urlencode(identity_id) .. "/sessions")
if resp.status ~= 204 and resp.status ~= 200 then
error("kratos: delete sessions HTTP " .. resp.status .. ": " .. resp.body)
end
end
c.flows = {}
function c.flows:create_login(opts)
opts = opts or {}
local params = {}
if opts.return_to then params[#params + 1] = "return_to=" .. urlencode(opts.return_to) end
if opts.refresh then params[#params + 1] = "refresh=true" end
if opts.login_challenge then params[#params + 1] = "login_challenge=" .. urlencode(opts.login_challenge) end
if opts.aal then params[#params + 1] = "aal=" .. urlencode(opts.aal) end
local qs = ""
if #params > 0 then qs = "?" .. table.concat(params, "&") end
return public_get("/self-service/login/browser" .. qs)
end
function c.flows:get_login(flow_id, cookie)
return public_get("/self-service/login/flows?id=" .. urlencode(flow_id), cookie)
end
function c.flows:get_login_admin(flow_id)
return admin_get("/admin/self-service/login/flows?id=" .. urlencode(flow_id))
end
function c.flows:submit_login(flow_id, payload, cookie)
return public_post("/self-service/login?flow=" .. urlencode(flow_id), payload, cookie)
end
function c.flows:create_registration(opts)
opts = opts or {}
local qs = ""
if opts.return_to then qs = "?return_to=" .. urlencode(opts.return_to) end
return public_get("/self-service/registration/browser" .. qs)
end
function c.flows:get_registration(flow_id, cookie)
return public_get("/self-service/registration/flows?id=" .. urlencode(flow_id), cookie)
end
function c.flows:submit_registration(flow_id, payload, cookie)
return public_post("/self-service/registration?flow=" .. urlencode(flow_id), payload, cookie)
end
function c.flows:create_recovery(opts)
opts = opts or {}
local qs = ""
if opts.return_to then qs = "?return_to=" .. urlencode(opts.return_to) end
return public_get("/self-service/recovery/browser" .. qs)
end
function c.flows:get_recovery(flow_id, cookie)
return public_get("/self-service/recovery/flows?id=" .. urlencode(flow_id), cookie)
end
function c.flows:submit_recovery(flow_id, payload, cookie)
return public_post("/self-service/recovery?flow=" .. urlencode(flow_id), payload, cookie)
end
function c.flows:create_settings(cookie)
return public_get("/self-service/settings/browser", cookie)
end
function c.flows:get_settings(flow_id, cookie)
return public_get("/self-service/settings/flows?id=" .. urlencode(flow_id), cookie)
end
function c.flows:submit_settings(flow_id, payload, cookie)
return public_post("/self-service/settings?flow=" .. urlencode(flow_id), payload, cookie)
end
c.identities = {}
function c.identities:get(id)
return admin_get("/admin/identities/" .. urlencode(id))
end
function c.identities:list(opts)
opts = opts or {}
local params = {}
if opts.per_page then params[#params + 1] = "per_page=" .. opts.per_page end
if opts.page then params[#params + 1] = "page=" .. opts.page end
if opts.credentials_identifier then
params[#params + 1] = "credentials_identifier=" .. urlencode(opts.credentials_identifier)
end
local qs = ""
if #params > 0 then qs = "?" .. table.concat(params, "&") end
return admin_get("/admin/identities" .. qs)
end
function c.identities:create(spec)
return admin_post("/admin/identities", spec)
end
function c.identities:update(id, spec)
return admin_put("/admin/identities/" .. urlencode(id), spec)
end
function c.identities:delete(id)
require_admin()
local resp = http.delete(admin_url .. "/admin/identities/" .. urlencode(id))
if resp.status ~= 204 and resp.status ~= 200 then
error("kratos: delete identity HTTP " .. resp.status .. ": " .. resp.body)
end
end
c.schemas = {}
function c.schemas:list()
require_public()
local resp = http.get(public_url .. "/schemas")
if resp.status ~= 200 then
error("kratos: list schemas HTTP " .. resp.status .. ": " .. resp.body)
end
return json.parse(resp.body)
end
function c.schemas:get(schema_id)
return public_get("/schemas/" .. urlencode(schema_id))
end
return c
end
return M