Authentication services
In this section the services needed for authentication will be created.
Authentication methods
Create methods for login with username and password, logout and obtaining refresh token.
/database/app/pck_app.pks
plsql
CREATE OR REPLACE PACKAGE pck_app AS -- Package provides methods for the application
PROCEDURE get_version( -- Procedure returns current version
r_version OUT VARCHAR2 -- Version number
);
PROCEDURE post_login( -- Procedure authenticates user and returns tokens
p_username APP_USERS.USERNAME%TYPE, -- User name (e-mail address)
p_password APP_USERS.PASSWORD%TYPE, -- Password
r_access_token OUT APP_TOKENS.TOKEN%TYPE, -- Token
r_refresh_token OUT APP_TOKENS.TOKEN%TYPE, -- Refresh token
r_user OUT SYS_REFCURSOR -- User data
);
PROCEDURE post_logout; -- Procedure invalidates access and refresh tokens
PROCEDURE post_refresh( -- Procedure re-issues access and refresh tokens
r_access_token OUT APP_TOKENS.TOKEN%TYPE, -- Token
r_refresh_token OUT APP_TOKENS.TOKEN%TYPE -- Refresh token
);
PROCEDURE get_heartbeat;
END;
/
/database/app/pck_app.pkb
plsql
CREATE OR REPLACE PACKAGE BODY pck_app AS
PROCEDURE get_version(
r_version OUT VARCHAR2
) AS
BEGIN
pck_api_settings.read('APP_VERSION', r_version);
END;
PROCEDURE post_login(
p_username APP_USERS.USERNAME%TYPE,
p_password APP_USERS.PASSWORD%TYPE,
r_access_token OUT APP_TOKENS.TOKEN%TYPE,
r_refresh_token OUT APP_TOKENS.TOKEN%TYPE,
r_user OUT SYS_REFCURSOR
) AS
v_uuid app_users.uuid%TYPE := pck_api_auth.auth(p_username, p_password);
BEGIN
IF (v_uuid IS NULL) THEN
pck_api_audit.wrn('Login error', pck_api_audit.mrg('username', p_username, 'password', '********'),v_uuid);
pck_api_auth.http_401('login.error.invalidUsernameOrPassword');
RETURN;
END IF;
pck_api_audit.inf('Login success', pck_api_audit.mrg('username', p_username, 'password', '********'), v_uuid);
pck_api_auth.reset(v_uuid, 'A');
pck_api_auth.reset(v_uuid, 'R');
r_access_token := pck_api_auth.token(v_uuid, 'A');
r_refresh_token := pck_api_auth.token(v_uuid, 'R');
OPEN r_user FOR
SELECT
u.uuid AS "uuid",
u.username AS "username",
u.fullname AS "fullname",
TO_CHAR(u.created, 'YYYY-MM-DD HH24:MI') AS "created"
FROM
app_users u
WHERE
u.uuid = v_uuid;
EXCEPTION
WHEN OTHERS THEN
r_access_token := NULL;
r_refresh_token := NULL;
pck_api_audit.err('Login error', pck_api_audit.mrg('username', p_username, 'password', '********'), v_uuid);
END;
PROCEDURE post_logout
AS
v_uuid app_users.uuid%TYPE := COALESCE(pck_api_auth.uuid, pck_api_auth.refresh('refresh_token'));
BEGIN
pck_api_auth.reset(v_uuid, 'A');
pck_api_auth.reset(v_uuid, 'R');
IF v_uuid IS NOT NULL THEN
pck_api_audit.inf('Logout success', '',v_uuid);
END IF;
EXCEPTION
WHEN OTHERS THEN
pck_api_audit.err('Logout error', NULL, v_uuid);
END;
PROCEDURE post_refresh(
r_access_token OUT APP_TOKENS.TOKEN%TYPE,
r_refresh_token OUT APP_TOKENS.TOKEN%TYPE
) AS
v_uuid app_users.uuid%TYPE := pck_api_auth.refresh('refresh_token');
BEGIN
IF v_uuid IS NULL THEN
pck_api_auth.http_401;
ELSE
pck_api_auth.reset(v_uuid, 'A');
pck_api_auth.reset(v_uuid, 'R');
r_access_token := pck_api_auth.token(v_uuid, 'A');
r_refresh_token := pck_api_auth.token(v_uuid, 'R');
END IF;
EXCEPTION
WHEN OTHERS THEN
r_access_token := NULL;
r_refresh_token := NULL;
pck_api_audit.err('Refresh error', NULL, v_uuid);
END;
PROCEDURE get_heartbeat
AS
v_uuid app_users.uuid%TYPE := pck_api_auth.uuid;
BEGIN
if v_uuid IS NULL THEN pck_api_auth.http_401; END IF;
EXCEPTION
WHEN OTHERS THEN
pck_api_audit.err('Heartbeat error', NULL, v_uuid);
END;
END;
/
Test
Test with Postmnan POST login
to get access and refresh tokens, POST logout
to revoke tokens, POST refresh
and GET heartbeat
with and without tokens to see the difference - check audit records.
sql
SELECT * FROM app_audit ORDER BY created DESC;