module namespace auth = 'urn:nubisware:muscle:fiber:auth';
import module namespace session = "http://basex.org/modules/session";
declare namespace b64 = "java:java.util.Base64";
declare namespace b64enc = "java:java.util.Base64$Encoder";
declare namespace b64dec = "java:java.util.Base64$Decoder";
declare variable $auth:config := map {
"keycloakurl" : "https://mykeycloak.org",
"realm" : "myrealm",
"clientid" : "myexamplepublicclient",
"client_redirect_uri" : "http://localhost:8984/auth/oidc-callback"
};
declare %private variable $auth:KEYCLOAK_BASE_URL :=
$auth:config?keycloakurl || "/auth/realms/" || $auth:config?realm || "/protocol/openid-connect";
declare %private variable $auth:KEYCLOAK_TOKEN_URL := $auth:KEYCLOAK_BASE_URL || "/token";
declare %private variable $auth:KEYCLOAK_LOGOUT_URL := $auth:KEYCLOAK_BASE_URL || "/logout";
declare %private variable $auth:KEYCLOAK_AUTH_URL := $auth:KEYCLOAK_BASE_URL || "/auth";
declare function auth:hex-to-base64url($tbe as xs:hexBinary) {
auth:bytes-to-base64url(convert:binary-to-bytes($tbe))
};
declare function auth:bytes-to-base64url($tbe as xs:byte*) {
b64enc:encodeToString(b64:getUrlEncoder(), $tbe)
};
declare function auth:extract-tokens-from-jwt($jwt as node()) as map(*){
let $b64decoder := b64:getDecoder()
let $t1 := $jwt/json/access__token/string()
let $t2 := tokenize($t1, "\.")[2]
let $t3 := convert:binary-to-string(convert:integers-to-base64(b64dec:decode($b64decoder, $t2)))
let $at := json:parse($t3)
let $t := $jwt/json/refresh__token/string()
return map{ "accesstoken" : $at, "refreshtoken" : $t, "bearer" : "Bearer " || $t1}
};
(: You can just raise an error with code aut:unauthorized from anywhere in your code to get here and be redirected to keycloak:)
declare
%rest:error("auth:unauthorized")
%rest:error-param("value", "{$value}")
function auth:unauthorized($value as map(*)?) {
web:redirect(web:create-url("/auth/login", $value))
};
(: Start OIDC login with code grant flow this makes it unnecessary to share secrets with a front facing application :)
declare
%rest:path("auth/login")
%rest:GET
%rest:query-param("error", "{$error}")
%rest:query-param("redirect", "{$redirect}", "/")
%output:method("html")
function auth:login-show-ep($error as xs:string?, $redirect as xs:string) {
let $params := map{
"client_id" : $auth:config?clientid, "response_type" : "code", "scope" : "openid",
"state" : ($redirect, "/")[1],
"redirect_uri" : $auth:config?client_redirect_uri
}
return web:redirect(web:create-url($auth:KEYCLOAK_AUTH_URL , $params))
};
(: That's the call back uri you will be redirected back after inserting your credentials in Keycloak :)
declare
%rest:path("auth/oidc-callback")
%rest:GET
%rest:query-param("error", "{$error}")
%rest:query-param("error_description", "{$error-description}")
%rest:query-param("session_state", "{$session-state}")
%rest:query-param("state", "{$state}")
%rest:query-param("code", "{$code}")
%output:method("html")
function auth:oidc-redirects(
$error as xs:string?, $error-description as xs:string?,
$session-state as xs:string?, $code as xs:string?, $state
) {
if(exists($error)) then
error("Unable to connect to auth service: " || $error-description)
else
let $body := web:create-url("",
map{
"grant_type" : "authorization_code",
"code" : $code,
"redirect_uri" : $auth:config?client_redirect_uri,
"client_id" : $auth:config?clientid,
"scope" : "openid"
})
let $token-response := http:send-request(