PolicyLogic
PolicyLogic is the brain of SpherAAA. The PolicyLogic uses a JavaScript compiler to write your Radius authentication call flow. JavaScript was chosen for its simplicity.
Type and environments
To provide a sandbox for development and testing, SpherAAA offers four environments.
- QA
- TEST
- STAGE
- PROD
Each environment has two categories:
- AUTH - Authentication flow
- ACCT - Accounting flow
PolicyLogic structure
When PolicyLogic retrieves a request for handling, we put all the available variables into a JSON Object, called "radius".
Variables groups - radius
radius contents the following groups: radius contains the following groups:
- eap — parsed information about the current EAP exchange.
- request — attributes from the RADIUS request.
- code — the RADIUS request/response code.
- session — RADIUS packet/session metadata (identifier, authenticator, length, source host/port).
- host — variables related to the requesting host/NAS.
- reply — attributes that SpherAAA will include in the RADIUS reply.
- config — entries from the config collection (platform settings available to PolicyLogic).
- user — user-related data (Identity, Realm, certificate details, etc.).
config
example:
Add the following entry to the Collections → config:
{
"Provider-Name": "My Provider Name",
"Session-Timeout": "1800",
"Authenticated-TTL": "1"
}
It will then be available in PolicyLogic as radius.config:
...
"config": [
{
"Provider-Name": "My Provider Name",
"Authenticated-TTL": "1",
"Session-Timeout": "1800"
}
]
Full examples of the radius
object
Below are full examples of the radius object for common request scenarios — Access-Request, Access-Accept, and Accounting. Use these as references when writing PolicyLogic.
{
"eap": {
"EAP-Code": "EAP-RESPONSE",
"EAP-Id": 125,
"EAP-Lenght": 79,
"EAP-Type": "EAP-TTLS"
},
"request": {
"Service-Type": "Framed",
"NAS-IP-Address": "192.168.200.1",
"NAS-Identifier": "NAS-2",
"EAP-Message": "0231004f158000000045170303004031e8575fdcf9804ec95333e48d75971a0958a08fd5a5fef63de82bdf27574380e7dea817843716b10c918456b46fed9d1117a9e4d1e4f53bebea1423d27e8ec0",
"NAS-Port-Type": "19",
"Framed-MTU": "1400",
"User-Name": "user@mydomain.com",
"Calling-Station-Id": "01-02-03-04-05-06",
"State": "aaa.spheralogic.com;1661152509",
"Unknown-0-187-0": "000fac04",
"Unknown-0-186-0": "000fac04",
"Acct-Session-Id": "42C4B84538D254BB",
"Message-Authenticator": "f605f97dbd864a5c64716dd5002d58a3",
"Called-Station-Id": "0C-60-DE-E4-BB-E6:SSID-SECURE",
"NAS-Port": "1",
"Connect-Info": "CONNECT 54Mbps 802.11g",
"Unknown-0-188-0": "000fac01"
},
"code": "ACCESS-REQUEST",
"session": {
"Spheraaa-Session-Id": "S-1661733604348",
"Packet-Identifier": 0,
"Authenticator": "b122f07a22f77a6cba6872dd795d3741",
"Packet-Length": 333,
"Source-Host-Port": "192.168.200.1:45969"
},
"host": {
"nasIpAddr": "192.168.200.1",
"note": "openwrt",
"type": "OPENWRT",
"dynPort": "3799",
"Source-Host-Port": "127.0.0.1:18812"
},
"reply": {},
"config": [
{
"proxy": {
"partners": [
{
"realms": [
"aaa.com",
"bbb.com"
],
"endpoint": [
"1.1.1.1",
"aaa.proxyaaa.com"
],
"auth-port": "1812",
"acct-port": "1813",
"name": "PARTNER_1",
"timeout": "5000",
"timeout-unreachable": "30000",
"balance-mode": "random"
},
{
"realms": [
"ccc.com"
],
"endpoint": "2.2.2.2",
"auth-port": "1812",
"acct-port": "1812",
"name": "PARTNER_2",
"timeout": "1000"
},
{
"realms": [
"ddd.com"
],
"endpoint": "3.3.3.3",
"auth-port": "1812",
"acct-port": "1813",
"name": "PARTNER_3"
},
{
"realms": [
"wlan.mnc001.mcc002.3gppnetwork.org",
"001_002.net"
],
"endpoint": "4.4.4.4",
"auth-port": "1812",
"acct-port": "1813",
"name": "PARTNER_MOBILE"
}
]
}
},
{
"Provider-Name": "My Provider Name",
"Authenticated-TTL": "2",
"Domain": "mydomain.com",
"Session-Timeout": "1800"
}
],
"user": {
"Identity": "user",
"Realm": "mydomain.com"
}
}
User group
The user group might hold User-Name related information. You can keep your variables here as well. If the username is in NAI format (email), then
radius.user
will hold the Identity
and Realm
variables.
For example, for User-Name = "user@domain.com"
...,
"user": {
"Identity": "user",
"Realm": "domain.com"
}
In the case of EAP-TLS authentication, the user group includes details of the user's provided certificate:
"user": {
"IssuerDN": "CN=aaa.spheralogic.com, OU=Wireless, O=SpheraLogic LLC-Root, L=NewYork, ST=NY, C=US",
"SerialNumber": "10453860482036592703",
"NotAfter": "Sun Aug 11 22:18:42 EDT 2024",
"NotBefore": "Fri Aug 12 22:18:42 EDT 2022",
"Identity": "eap",
"SubjectDN": "CN=anonymous@company.com, OU=USERID_NAME, O=SpherAAA_LLC-Client, L=NewYork, ST=NY, C=US",
"SessionID": "62f70ac8005f4821c7db5cd1b838f7bacb5eb567d8927ac32fd5b1a0616bbde1",
"Realm": "local.com"
},
You can later use these variables as references in your PolicyLogic.
var realm = radius.user['Realm'];
PolicyLogic syntax
JavaScript 101
JavaScript has proven itself to be a very easy language to comprehend and immediately put into use. However, it comes with a set of basic principles that could be baffling to newcomers:
- While the ECMAScript specification lists semicolons as optional, using them in all assignment statements and function declarations can protect against unintentional results.
- Variables are
undefined
by default which is a different from beingnull
. To check if variable is defined, the basic conditionif (variable)
is a sufficient check. - JavaScript introduces the concept of truthy and falsy (or falsey) values. All values except
undefined
,null
,false
,-0
,+0
,NaN
, and''
are truthy and evaluate totrue
during comparison. - Loose typing requires understanding rules behind type coercion:
3 + 3 + "3"
evaluates to63
whereas"3" + 3 + 3
yields333
. This implicit conversion stems from left-to-right arithmetic and when a string object is found, the operation continues as a concatenation. - The same type of coercion applies to a comparison invoked with the
==
operator. To avoid coercing the type when comparing values, it's good to use the===
operator, which compares both the value and the type, for example,1 == true
but1 !== true
. - For all operations involving numbers, a good habit is to use the built-in
parseInt
andparseFloat
functions or a shorter+variable
expression syntax to perform number conversion. - Just like Bash, conditional expressions could be simplified with the
&&
and||
operators so that1 == "1" && print("yes")
simulates the longerif (1 == "1") { print("yes"); }
syntax. - A function always expects an arbitrary number of positional arguments, rendering missing values as
undefined
. The predefined array-likearguments
variable exposes the index access with square brackets. The only ways to access this variable are througharguments[i]
andarguments.length()
.
Functions
Response
- success
Depends on Radius request type, functions return success response to client. For instance:
Radius Request | Response |
---|---|
Access-Request | Access-Accept |
Acct-Request | Acct-Response |
CoA-Request | CoA-Ack |
DM-Request | DM-Ack |
Status-Request | Access-Accept |
For example, this statement will return Access-Accept with Reply-Message = "Success Auth".
radius.reply['Reply-Message'] = "Success Auth";
success();
You can also pass the value of the Reply-Message AVP directly to the success() function:
success("Success Auth");
- fail
Depends on Radius request type, functions return failure response to client. For instance:
Radius Request | Response |
---|---|
Access-Request | Access-Reject |
Acct-Request | Acct-Response |
CoA-Request | CoA-Nack |
DM-Request | DM-Nack |
Status-Request | Access-Reject |
For example, we will return Access-Reject with Reply-Message = "Invalid Username or Password".
radius.reply['Reply-Message'] = "Invalid Username or Password";
fail();
fail(replyMessage)
- returns failure response with providede replyMessage
fail("Access denided");
Requests
- RadiusRequest
RadiusRequest(code, dest_ip, dest_port, timeout)
The RadiusRequest
function generates a Radius-Request and returns the request result.
Parameter | Type | Description | Default |
---|---|---|---|
code |
string | Radius Code — Check for supported codes | — |
dest_ip |
string | IP address or FQDN of destination RADIUS or NAS server | — |
dest_port |
integer | Destination port (e.g., 1812, 1813, 3799, or any) | 1812 / 1813 / 3799 |
timeout |
integer (ms) | Response timeout in milliseconds for the request | 2000 |
- RadiusProxy
The RadiusProxy()
function generates a Radius-Request and returns the request result. Parameters for the RadiusProxy can be configured either by setting them using radius.proxy['Parameter-Name']
or directly as instance variables.
To proxy or send RADIUS packets to another AAA server, we should define Partners AAA IP in the NAS configuration (as regular NAS). If the NAS Host is not defined in the NAS configuration and the radsec_cert_id
parameter is set, SpherAAA enables Dynamic Peer Discovery (WBA OpenRoaming, eduroam) RFC7585, to determine the AAA server's IP or FQDN and port by querying NAPTR, SRV, and A records from the DNS server using the realm value from the EAP-Identity.
Below are the supported parameters for the function:
Parameter / method | Alias (radius.proxy) | Type | Default | Description |
---|---|---|---|---|
send() |
— | method | — | Sends the RADIUS request to the destination (dst ) using attributes in radius.request . Populates radius.reply with the proxy response. |
dst |
radius.proxy['Proxy-Address'] |
string (IP or FQDN) | — | Destination RADIUS or NAS server address. |
dst_port |
radius.proxy['Proxy-Address-Port'] |
integer | 1812 / 1813 / 3799 (or any) | Destination port. |
timeout |
radius.proxy['Proxy-Timeout'] |
integer (ms) | 2000 | Response timeout in milliseconds. |
timeout_unreachable |
radius.proxy['Proxy-Timeout-Unreachable'] |
integer (ms) | — | Mark server as unreachable for this duration (ms) to avoid using it. |
name |
radius.proxy['Proxy-Provider'] |
string | — | Host-group name required by SpherAAA internal load‑balancer. |
balance_mode |
radius.proxy['Proxy-Balance-Mode'] |
string | random / round-robin |
Load‑balancing algorithm for proxied endpoints. EAP session persistence supported. |
secret |
radius.proxy['Proxy-Secret'] |
string | — | Shared secret for the proxy server. |
radsec_cert_id |
radius.proxy['Proxy-Radsec-CertId'] |
string | — | Certificate ID from the RADSEC Certificates menu (for RADSEC connections). |
disable_radsec_verify |
radius.proxy['Proxy-Radsec-DisableHostVerfiy'] |
boolean | false |
Disable SSL certificate verification for RADSEC connections when true . |
The destination IP-Address can be dynamically retrieved from configuration (config
collection) or manually assigned.
Example:
const proxyServer = new RadiusProxy();
proxyServer.code = radius.code;
proxyServer.dst = "1.2.3.4"; //radius.proxy['Proxy-Address'] = "1.2.3.4";
proxyServer.dst_port = "1812"; // radius.proxy['Proxy-Address-Port'] = "1812";
proxyServer.timeout = "2000";
proxyServer.name = "MY_PROXY_PROVIDER";
proxyServer.timeout_unreachable = "10000";
proxyServer.balance_mode = "round-robin";
proxyServer.dpd = "false";
const proxyResult = proxyServer.send();
//log(proxyResul);
and log
result
{"reply":
{
"Class":"TYPE=X",
"Class":"ID=USERID"
},
"code":"ACCESS-ACCEPT"
}
- getProxySettings
getProxySettings(realm)
loops over the config.proxy
group and retrieves proxy parameters using radius.user ['Realm'] parameter
As a result of getProxySettings(realm)
, radius.proxy
group will be populated with the below parameters:
Parameter | Description |
---|---|
radius.proxy['Proxy-Address'] |
Destination IP address or FQDN of the partner AAA server. |
radius.proxy['Proxy-Address-Port'] |
Port of the partner AAA server (e.g., 1812, 1813, 3799). |
radius.proxy['Proxy-Timeout'] |
Response timeout in milliseconds when waiting for a reply from the partner AAA server (default: 2000 ms). |
radius.proxy['Proxy-Timeout-Unreachable'] |
Duration in milliseconds to mark the server as unreachable and avoid using it (equivalent to timeout-unreachable ). |
radius.proxy['Proxy-Provider'] |
Partner name value from configuration; required by SpherAAA's internal load‑balancer. |
radius.proxy['Proxy-Balance-Mode'] |
Load‑balancing algorithm for proxied endpoints. Supported values: random , round-robin . EAP session persistence is supported. |
radius.proxy['Proxy-DPD'] |
Enable Dynamic Peer Discovery (e.g., OpenRoaming, eduroam) to resolve the AAA server IP/FQDN by querying NAPTR/SRV/A records using the user realm. |
Here's an example of obtaining a destination address dynamically based on the user realm (domain) using getProxySettings
.
Considering this entry on the config
collection (created by default):
{
"proxy": {
"partners": [{
"name": "PARTNER1",
"realms": ["partner1.com","partner1.net"],
"endpoint": ["1.1.1.1", "aaa.proxyaaa.com"],
"auth-port": "1812",
"acct-port": "1813",
"name": "PARTNER_1",
"timeout": "5000",
"timeout-unreachable": "30000",
"balance-mode": "random"
},{
"name": "DPD-PARTNER",
"realms": [
"partner-dpd.com"
],
"endpoint": "someuniquename.com",
"port": "2083",
"timeout": "2000",
"dpd": "true"
},
{
"name": "PARTNER2",
"realms": [
"partner2.com"
],
"endpoint": "2.2.2.2",
"port": "1812",
"timeout": "2000"
},
{
"name": "PARTNER3",
"realms": [
"partner3.com"
],
"endpoint": "3.3.3.3",
"auth-port": "1812",
"timeout": "2000"
}
]
}
}
We can run the below code to get a dynamically obtained destination address and send a Radius-Proxy request.
function doProxyCheck() {
var realm = radius.user['Realm'];
var proxySettings = getProxySettings(realm);
if (!proxySettings) {
return false;
}
var proxyDPD = radius.proxy['Proxy-DPD'];
var proxyInstance = new RadiusProxy();
if (proxyDPD) {
// If Dynamic Peer Discovery is enabled and resolved AAA was never stored by the platform,
// we must assign the RADSEC server certificate using the certificate ID from
// "RADSEC Certificates menu, AAA RADSEC Certificates".
// Example:
// proxyDPD['cert-id'] = "67b0e41be9433543f0fdfa85";
// Similarly, set the RADIUS secret if it's different from "radsec" as per RFC.
// Here, we retrieve it securely from a vault.
proxyDPD['secret'] = readFromVault("or_secret");
}
var proxyResult = proxyInstance.send();
return proxyResult !== undefined && proxyResult !== null ? proxyResult : false;
}
The result of the proxy will be populated into the radius.reply
group for further processing.
- RadiusCodes
Radius Codes
Type | Request | Success Response | Failure Response |
---|---|---|---|
Auth | access-request |
access-accept |
access-reject |
Acct | acct-request |
acct-response |
— |
Disconnect-Message | dm-request |
dm-ack |
dm-nack |
Change-of-Authorization | coa-request |
coa-ack |
coa-nack |
Status | status-request |
status-response |
— |
Cache Collection functions
- queryMany/queryAll
queryMany( queryKey, queryValue, collectionName )
queryAll( collectionName )
Query collection by specifying the query key and value. As a result, you will get all entries for specified key.
Parameter | Description |
---|---|
queryKey |
The key to finding an existing entry. |
queryValue |
The value of the key when looking up an entry. |
collectionName |
The collection's name. |
returns |
The query result returns a JSON array (e.g., [{"key1":"val1"}, {"key2":"val2"}] ). Returns false if the query fails or the entry does not exist. |
For instance:
// Check for the PPSK Authentication.
// Assign VLANs dynamically.
//
function checkPPSK() {
if (radius.request['User-Name'] == radius.request['User-Password']) {
var dbResult = queryMany("Called-Station-Id", radius.request['Called-Station-Id'], "ppsk");
if (dbResult) {
for (i = 0; i <= dbResult.length - 1; i++) {
radius.reply['tag'][i] = {};
radius.reply['tag'][i]['Tunnel-Password'] = dbResult[i]['Tunnel-Password'];
radius.reply['tag'][i]['Tunnel-Private-Group-Id'] = dbResult[i]['Tunnel-Private-Group-Id'];
radius.reply['tag'][i]['Tunnel-Type'] = dbResult[i]['Tunnel-Type'];
radius.reply['tag'][i]['Tunnel-Medium-Type'] = dbResult[i]['Tunnel-Medium-Type'];
}
radius.reply['Reply-Message'] = "Success Auth";
//
// Store request in the "Session" collection with TTL 1hr
//
// function: upsertEntry(collectionName, object, TTL, indexName, indexValue);
//
upsertEntry("sessions", radius.request, 3600, "Calling-Station-Id", radius.request['Calling-Station-Id']);
success();
return true;
}
return false;
}
}
- queryOne
queryOne( queryKey, queryValue, collectionName )
Query collection by specifying the query key and value. As a result, you will receive only one entry. To query all entries, please use queryAll
Parameter | Description |
---|---|
queryKey |
The key to find an existing entry. |
queryValue |
The value of the key when looking up an entry. |
collectionName |
The collection's name. |
returns |
The query result returns a JSON array (e.g., [{"key1":"val1"}, {"key2":"val2"}] ). If the query fails or no entry exists, returns false . |
{
"status":"failed"
}
For instance:
var dbResult = queryOne("User-Name", radius.request['User-Name'], "users");
if(dbResult['result'] != "failed" && dbResult['User-Password'] == radius.request['User-Password'] ){
radius.reply['Reply-Message'] = "Success Auth";
//
// Store request in the "Session" collection with TTL 1hr
//
// function: upsertEntry(collectionName, object, TTL, indexName, indexValue);
//
upsertEntry("sessions", radius.request, 3600, "Calling-Station-Id", radius.request['Calling-Station-Id']);
success();
}
}
- insertEntry
insertEntry( collectionName, jsonObject, ttl )
Persist a JSON object in a collection using the Time-to-Live option. When the TTL expires, the entry will be removed.
Parameter | Description |
---|---|
collectionName |
The collection's name. If the collection does not exist, it will be created automatically. |
jsonObject |
Any valid JSON object to be stored. |
TTL |
Time‑to‑Live in seconds (e.g., 1 = 1 second, 3600 = 1 hour, 7200 = 2 hours). |
For instance, we will add a custom made JSON object to the collection for a period of 24 hours.
var sessionVar = {
"AccountId": 123456,
"Calling-Station-Id": radius.request['Calling-Station-Id'],
"Called-Station-Id": radius.request['Called-Station-Id']
};
insertEntry( "auth_sessions", sessionVar, 86400 );
- upsertEntry
upsertEntry( collectionName, jsonObject, ttl, key, value )
If an entry with the key exists, update it; otherwise, use the Time-to-Live option to persist a JSON object in a collection. The entry will be removed after the TTL expires.
Parameter | Description |
---|---|
collectionName |
The collection's name. If the collection does not exist, it will be created automatically. |
jsonObject |
Any valid JSON object. If key is provided, the jsonObject will be saved under the specified key →value . |
TTL |
Time‑To‑Live in seconds. Examples: 1 (1 second), 3600 (1 hour), 7200 (2 hours), etc. |
key |
The key used to find or index an existing entry. If provided, an index on this key will be created. |
value |
The value of the key when looking up or upserting an existing entry. |
For instance, we will add a custom made JSON object to the collection for a period of 24 hours.
var sessionVar = {
"AccountId": 123456,
"Calling-Station-Id": radius.request['Calling-Station-Id'],
"Called-Station-Id": radius.request['Called-Station-Id']
};
upsertEntry( "auth_sessions", sessionVar, 86400, "Calling-Station-Id", radius.request['Calling-Station-Id'] );
- deleteEntry
deleteEntry( key, value, collectionName )
If the key already exists in an entry, it will be removed, and 1 will be returned as a result; otherwise, 0 will be returned.
Parameter | Description |
---|---|
key |
The key to finding an existing entry. |
value |
The value of a key when looking up an existing entry. |
collectionName |
The collection's name. |
deteleEntry( "Calling-Station-Id", radius.request['Calling-Station-Id'], "sessions" );
EAP
- EAP-TTLS
EAP-TTLS is another authentication method that uses a tunneled TLS connection. Unlike EAP-TLS, EAP-TTLS does not require digital certificates on the client side, which can make it easier to deploy in some environments. During the authentication process, the client sends its credentials to the authentication server in an encrypted TLS tunnel. The server then verifies the credentials and sends an authentication response back to the client. If the authentication is successful, the server and client establish a secure TLS tunnel, and the client is granted access to the network resources.
SpherAAA supports EAP-TTLS both with PAP and EAP-GTC inner-tunnel authentication methods. Before starting with EAP-TTLS, please import or generate a server certificate using this instruction.
Usage: var eapttls = new EapTTLS();
Parameters:
Parameter | Allowed values / Type | Default | Description |
---|---|---|---|
cert_id |
string (Certificate ID from Secure → EAP Server Certificates) | environment default certificate | Specify which server certificate to use for EAP‑TTLS. If not set, the environment's default certificate is used. |
tunnel_auth |
PAP , GTC , or PAP,GTC |
PAP,GTC |
Phase‑2 (inner) authentication method(s) supported inside the TTLS tunnel. |
enabled_tls_versions |
comma-separated list: TLSv1.0 , TLSv1.1 , TLSv1.2 (TLSv1.3 support in development) |
TLSv1.1,TLSv1.2 |
Enabled TLS protocol versions for the TTLS handshake. |
enabled_ciphers |
comma-separated list of cipher suite names (see Cipher Suites list) | platform defaults | Enabled TLS cipher suites for the TTLS tunnel; use to restrict or permit specific suites. |
start() |
method | — | Starts the EAP‑TTLS offer and authentication process. Returns EAP states: Starting , Handshaking , ApplicationData . |
To start the EAP-TTLS process, we can call the internal function EapTTLS() and while the function returns EAP-State values, the process needs to continue.
Until we reach the ApplicationData
state, in which SpherAAA and the client exchange credentials within a TLS tunnel. In this state, SpherAAA adds a new parameter Inner-Auth-Method
to
request
group with the value of the inner auth method: EAP-GTC, PAP or MSCHAPv2.
1 2 3 4 5 6 |
|
Below you can find example on how EapTTLS
is implemented (included to default auth file):
// Check for EAP-TTLS Authentication. If an "eap" group is available
// and if we are not in Inner-Tunnel Auth state, then just return back
// to EAP-TTLS until handshake process is done and we get Inner-Tunnel
// credentials.
//
if (radius.eap && !radius.request['Inner-Auth-Method']) {
// Create a new object for handling EAP-TTLS Authentication.
var eapttls = new EapTTLS();
// Use an alternate certificate when a request originates from the realm "otherdomain.com".
// if (radius.user.Realm == "otherdomain.com" ) {
// eapttls.cert_id = "6461706ef4befabdc81e6d1a";
// }
// Specify Phase2 Authentication method for this request
// if (radius.user.Realm == "allowonlypap.com" ) {
// eapttls.tunnel_auth = "PAP";
// }
// Specify cipher suites for this request
// if (radius.user.Realm == "specific.com" ) {
// eapttls.enabled_ciphers = "TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384";
// eapttls.enabled_tls_versions = "TLSv1.2" ;
// }
// Start EAP-TTLS authentication
var ttlsReturn = eapttls.start();
// If an error occurs, set the Reply-Message accordingly
// if (ttlsReturn['eap-error'] !== undefined)
// radius.reply['Reply-Message'] = ttlsReturn['eap-error'];
// Check if EapTTLS process returned any result
// Usually it will return EAP Exchange status
// like: Starting, Handshaking, ApplicationData
//
if (ttlsReturn) {
return;
}
}
return
function to exist PolicyFlow and continune with EAP Handshake process.
- EAP-TLS
EAP-TLS is a strong authentication method that uses digital certificates for mutual authentication between the client and the authentication server. During the authentication process, the client presents its digital certificate to the server for verification, and the server presents its own certificate to the client. If the certificates are valid and trusted, the client and server establish a secure TLS connection, and the client is granted access to the network resources.
Usage: var eaptls = new EapTLS();
Parameters:
Parameter | Allowed values / Type | Default | Description |
---|---|---|---|
cert_id |
string (Certificate ID from Secure → EAP Server Certificates) | environment default certificate | Specify which server certificate to use for EAP‑TLS. If not set, the environment's default certificate is used. |
enabled_tls_versions |
comma-separated list: TLSv1.1 , TLSv1.2 and TLSv1.3 |
TLSv1.1,TLSv1.2,TLSv1.3 |
Enabled TLS protocol versions for the EAP‑TLS handshake. |
enabled_ciphers |
comma-separated list of cipher suite names (see Cipher Suites list) | platform defaults | Enabled TLS cipher suites for the EAP‑TLS tunnel; use to restrict or permit specific suites. |
ocsp_enabled |
boolean (true / false ) |
false |
When true , SpherAAA will query the OCSP responder for client certificate status and populate user.X509.OCSP_Response . SpherAAA will not automatically reject requests based on OCSP — decision remains in PolicyLogic. See OCSP Response section. |
start() |
method | — | Starts the EAP‑TLS offer and authentication process. Returns EAP states such as Starting , Handshaking , ApplicationData . |
To start the EAP-TTLS process, we can call the internal function EapTLS() and while the function returns EAP-State values, the process needs to continue.
Until we reach the ApplicationData
state, in which SpherAAA and the client authenticating each others. In this state, SpherAAA adds a new parameter Inner-Auth-Method
to
request
group with the value X509
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
You can verify the client certificate by calling checkTLSCert()
- EAP-PEAP
EAP-PEAP is a secure authentication method that encapsulates the EAP within a TLS tunnel to protect user credentials. It is widely used in wireless networks and VPNs for secure access.
SpherAAA supports EAP-PEAP
both with MSCHAPv2
and GTC
inner-tunnel authentication methods, and implements RFC's draft-josefsson-pppext-eap-tls-eap-05 and draft-kamath-pppext-peapv0-00.
Before starting with EAP-PEAP, please import or generate a server certificate using
this instruction.
Usage: var eappeap = new EapPEAP();
Parameters:
Parameter | Allowed values | Default | Description |
---|---|---|---|
cert_id |
Certificate ID (string) from Secure → EAP Server Certificates | environment default certificate | Specify the server certificate to use for PEAP. If not set, SpherAAA uses the environment's default certificate. |
enabled_tls_versions |
TLSv1.1 , TLSv1.2 (support for TLSv1.3 in development) |
TLSv1.1,TLSv1.2 |
Enabled TLS protocol versions for the PEAP tunnel. |
enabled_ciphers |
Comma-separated list of cipher suite names | See cipher suites list | Enabled TLS cipher suites for the PEAP tunnel (refer to the cipher suites configuration). |
tunnel_auth |
MSCHAPv2 , GTC , MSCHAPv2,GTC |
MSCHAPv2,GTC |
Phase‑2 (inner) authentication method(s) supported inside the PEAP tunnel. |
peap_version |
Specific PEAP version string or allow negotiation | negotiate with client | Specify a PEAP version or allow SpherAAA to negotiate per the PEAP specification (see RFC/draft: https://datatracker.ietf.org/doc/html/draft-josefsson-pppext-eap-tls-eap-05#section-2.3). |
eappeap.start() |
— | — | Starts the EAP‑PEAP offer and authentication process. Returns EAP states: Starting , Handshaking , ApplicationData . |
To start the EAP-PEAP process, we can call the internal function EapPEAP() and while the function returns EAP-State values, the process needs to continue.
Until we reach the ApplicationData
state, in which SpherAAA and the client exchange credentials within a TLS tunnel. In this state, SpherAAA adds a new parameter Inner-Auth-Method
to
request
group with the value of the inner auth method: EAP-GTC or MSCHAP2.
- OCSP Response
The OCSP response will be available in the user.X509.OCSP_Response
variable and can have one of the following values:
OCSP Response | Meaning |
---|---|
good | the certificate is valid. |
revoked | the certificate has been revoked. |
unknown | the certificate's status is unknown to the OCSP. |
error | SpherAAA couldn't connect to the certificate authority's OCSP server. |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
You can refer to the example below, which includes a function for verifying the certificate status.
// This function checks for EAP-TLS authentication using OCSP Responder result and returns a boolean
// more info https://spheralogic.com/wiki/policy/#-ocsp-client
function verifyEapTls(ocsp_enabled) {
if (radius.request['Inner-Auth-Method'] === "X509") {
// Check if OCSP is enabled
if (ocsp_enabled) {
let certStatus = radius.user.X509.OCSP_Response;
// Verify the certificate status using OCSP response
if (certStatus === "good") {
return true; // Certificate is valid
} else {
log("Certificate with Serial Number " + radius.user.X509.SerialNumber + " has been rejected due to the status " + certStatus);
return false; // Certificate is rejected
}
} else {
// OCSP is disabled, perform internal verification
if (checkTLSCert()) {
return true; // Certificate is valid
}
}
} else {
radius.reply['Reply-Message'] = "Certificate not found";
return false; // Certificate is not found
}
}
- EAP-AKA Privacy
The EAP-AKA Privacy is permanent identity of an EAP client using RSA-OAEP encryption scheme with a 2048-bit RSA key and SHA-256 hashing. The encrypted permanent identity is sent to the authentication server with an optional key identifier field, CertificateSerialNumber=1234567890
to help the server locate the private key to decrypt the identity. The client uses the RSA public key of the server to encrypt the identity and Base64 encoding of the encrypted data provides a string of 344 ASCII characters. The 2048-bit key size is necessary to avoid exceeding the maximum transfer unit of the AVP value.
The EapAkaIdentity()
function initiates an Access-Challenge
request by setting the EAP-Type to "request" and the EAP-SubType to AT_ANY_ID_REQ
. The AAA server expects to receive an Access-Request
containing an encrypted AKA_IDENTITY
encoded using base64. Upon successful decryption, the function returns AKA-Identity-Done
which provides information about the decrypted permanent identity and certificate serial number from the request in the user
group:
"user": {
"3GPP-Identity": {
"Permanent-Identity": "0123456789012345@wlan.mnc456.mcc123.3gppnetwork.org",
"Certificate-Serial-Number": "1234567890"
},
"Identity": "anonymous",
"Realm": "wlan.mnc456.mcc123.3gppnetwork.org",
"Timestamp": "2023/01/01 00:00:00"
},
- Cipher Suites
The following cipher suites are supported by default and can be used for EAP authentication by setting the enabled_ciphers
parameter:
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_3DES_EDE_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_CBC_SHA
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
TLS_DHE_DSS_WITH_AES_128_CBC_SHA
These cipher suites ensure secure communication and can be customized for specific authentication scenarios.
Utilites
Base64
Base64 works by converting groups of three 8-bit binary bytes into four 6-bit characters, which are then represented using the standard ASCII character set. This process results in a larger output size compared to the input size, but the encoded data can be easily transmitted over communication channels that may not support binary data.
For example, if we take the string "Hello, World!" and convert it to Base64 encoding, the resulting output would be "SGVsbG8sIFdvcmxkIQ==". This encoding can then be sent as a text message or used in a URL without any issues.
Base64.encode(sting)
var b64 = Base64.encode("test");
output: b64="dGVzdA=="
Base64 encoding is reversible, meaning that the original binary data can be retrieved by decoding the Base64 string using a Base64 decoder. This makes it a useful tool for encoding and decoding data for various purposes, such as data transmission and data storage.
Base64.decode(base64_string)
var text = Base64.decode("dGVzdA==");
output: text="test";
Check TLS Certificate
checkTLSCert()
This function uses the certificate serial number to retrieve client EAP-TLS certificate information from the SpherAAA's internal PKI. When a certificate exists and not revoked/disabled , the return value is certificate data as a JSON:
{
"comment": "Generated by SpherAAA. Root Cert SN 14520661811939377238",
"created": {
"$date": 1662143034000
},
"expires": {
"$date": 1725215034000
},
"subject": "CN=anonymous@company.com,OU=USERID_NAME,O=SpherAAA-Client,L=City,ST=NY,C=US",
"issuer": "CN=aaa.spheralogic.com,OU=1,O=SpheraLogic LLC-Root,L=NewYork,ST=NY,C=US",
"serial_number": "17588163288774580330",
"revoke_status": false
}
false
if the certificate has been revoked or not found.
Crypto
Encryption: The encryption method takes in a secret key and a string of data to encrypt. It uses the Advanced Encryption Standard (AES) algorithm in Electronic Codebook (ECB) mode with PKCS5Padding to encrypt the data ("AES/ECB/PKCS5Padding"). The method returns a Base64-encoded string representation of the encrypted data.
Crypto.encrypt(plain_text, key)
Parameter | Description |
---|---|
plain_text |
Input text |
key |
Key with a size of 16, 24, or 32 bytes |
Example
var clear_text = "my private data";
var key = "gSp42mSu75EZaEgZ";
var encryted_text = Crypto.encrypt(clear_text,key);
Output: "jpiGHk7IU21tAoduyXFf7A=="
Decryption: The decryption method takes in a secret key and a Base64-encoded string of data to decrypt. It uses the same AES algorithm in ECB mode with PKCS5Padding to decrypt the data ("AES/ECB/PKCS5Padding"). The method returns the decrypted data as a string.
Crypto.decrypt(encryted_text, key)
Parameter | Description |
---|---|
encryted_text |
Encrypted input text (Base64-encoded string) |
key |
Secret key with a size of 16, 24, or 32 bytes |
Example
var encryted_text = "jpiGHk7IU21tAoduyXFf7A==";
var key = "gSp42mSu75EZaEgZ";
var plain_text = Crypto.decrypt(encryted_text,key);
Output: "my private data"
EntraIDAuth
The EntraIDAuth
integration uses ROPC Flow (username + password sent directly to Entra ID). This allows users to authenticate via their Entra ID credentials directly in a RADIUS-based flow - e.g., logging into Wi-Fi or VPN with a username/password that’s actually validated against Microsoft Entra ID.
Constructor Properties:
Parameter | Type | Description |
---|---|---|
tenant_id |
string | Tenant ID (Directory ID) of the Azure Entra ID instance. Required to target the specific tenant for authentication. |
client_id |
string | Application ID (Client ID) registered in Entra ID for authentication. |
client_secret |
string | Secret key associated with the application used for secure access. |
EntraIDAuth.checkCredentials
checkCredentials(user, pass)
This method validates user credentials (username and password) against the Entra ID authentication service.
Parameters:
Parameter | Type | Description |
---|---|---|
user |
string | The username to verify. |
pass |
string | The password associated with the username. |
Returns a JSON object if the verification is completed.
Example for success verification:
{
"exists": true,
"acct": 0,
"oid": "dd123212-xxxx-4dfxxxx7-xxxx-xxxxxx",
"platf": "14",
"puid": "sdfsdf23434234",
"tid": "123123-3614-12323-8edc-adf342g5t56",
"unique_name": "user@example.net",
"upn": "user@example.net"
}
Example for failed verification:
{
"error": "invalid_grant",
"error_description": "AADSTS50126: Error validating credentials due to invalid username or password. Trace ID: 3a3bf7a7-5b00-4fc6-af33-36f001615400 Correlation ID: f6d8bcee-2193-4ec5-9b4d-0df48b327ac1 Timestamp: 2024-12-14 01:34:50Z",
"error_codes": [50126],
"timestamp": "2024-01-01 00:00:00Z",
"trace_id": "3a3bf7a7-5b00-4fc6-af33-36f001615400",
"correlation_id": "f6d8bcee-2193-4ec5-9b4d-0df48b327ac1",
"error_uri": "https://login.microsoftonline.com/error?code=50126"
}
Usage Example:
After receiving username
and password
from EAP-TTLS PAP/GTC, EAP-PEAP GTC, we can call the function below to verify the credentials against EntraID. Here we are using the readFromVault()
function to retrive stored encrypted data from the platform.
function EntraIDAuth(username, password) {
// Read credentials from Vault
const clientId = readFromVault("client_id");
const tenantId = readFromVault("tenant_id");
const clientSecret = readFromVault("client_secret");
// Validate required parameters
if (!clientId || !tenantId || !clientSecret) {
return false;
}
// Initialize EntraIDAuth object
const authClient = new EntraIDAuth();
// Set parameters for the auth client
authClient.client_id = clientId;
authClient.tenant_id = tenantId;
authClient.client_secret = clientSecret;
// Attempt authentication
const response = authClient.checkCredentials(username, password);
// Check if authentication was successful
return !!(response && response.exists);
}
EntraIDAuth.checkUser
checkUser(object)
Checks if a object exists in Entra ID and retrieves their details. This method queries the Microsoft Graph API to fetch information for the specified user. It is useful for scenarios like EAP-TLS authentication, where you need to verify that a user is still active in Entra ID based on certificate information.
Parameters:
object
(string): The user'suserPrincipalName
(e.g.,user@example.com
) orobjectId
(oid) to look up in Entra ID.
Returns a JSON object containing the user's details from the Microsoft Graph API if the user is found. The response object will include an exists: true
property upon a successful lookup.
Usage Example:
function checkUserInEntraID(object) {
// Read credentials from Vault
const clientId = readFromVault("client_id");
const tenantId = readFromVault("tenant_id");
const clientSecret = readFromVault("client_secret");
// Validate required parameters
if (!clientId || !tenantId || !clientSecret) {
log("Entra ID credentials not found in vault.");
return false;
}
// Initialize EntraIDAuth object
const authClient = new EntraIDAuth();
// Set parameters for the auth client
authClient.client_id = clientId;
authClient.tenant_id = tenantId;
authClient.client_secret = clientSecret;
// Check if the user exists
const response = authClient.checkUser(object);
// Return true if the user exists, otherwise false
return !!(response && response.exists);
}
Example Response:
A successful response will contain the user's details from the Graph API and an exists: true
flag.
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
"businessPhones": [],
"displayName": "User",
"givenName": null,
"jobTitle": null,
"mail": "user@example.com",
"mobilePhone": null,
"officeLocation": null,
"preferredLanguage": "en",
"surname": null,
"userPrincipalName": "user@example.com",
"id": "34234-324-4dxxxxf7-34234-xxxxxxx",
"exists": true
}
A failed response indicates that the user was not found or an error occurred, and will include an exists: false
flag.
{
"error": "Graph API error: HTTP 404",
"exists": false,
"details": "{\"error\":{\"code\":\"Request_ResourceNotFound\",\"message\":\"Resource 'user-not-found' does not exist or one of its queried reference-property objects are not present.\",\"innerError\":{\"date\":\"2024-04-30T01:15:08\",\"request-id\":\"xxx-a974-xxxxx-9d88-xxxx\",\"client-request-id\":\"xxxx-a9xxx74-4802-9d88-xxxx\"}}}"
}
HMAC
The HMAC algorithm takes a message and a secret key as input and produces a fixed-size hash value as output.
hmac(algorithm, message, secret_key)
The HMAC algorithm is commonly used to verify the integrity and authenticity of a message. To create an HMAC, the message is first combined with the secret key using a specific algorithm, such as SHA-256 or MD5. The resulting hash is then combined with the secret key again using the same algorithm. This process creates a unique signature for the message that can only be verified by someone who knows the secret key.
Supported alogorithims:
- HmacMD5
- HmacSHA1
- HmacSHA224
- HmacSHA256
- HmacSHA384
- HmacSHA512
var algo = "HmacSHA256";
var message = "users private data";
var secret_key = "secret";
var hashed_value = hmac(algo, message, secret_key);
output: hashed_value="10e80bacf0225e6b3defe6664a7f026f54d021a16a64a38d6ad29a848113e51e"
HTTPClient
This function designed to create an HTTP client for making HTTP requests. It's a constructor function that can be used to create instances of an HTTP client.
Here's a breakdown of the key properties and methods defined within the HTTPClient
function:
Property | Type | Default | Description |
---|---|---|---|
url |
string | — | The URL to which the HTTP/HTTPS request will be sent. |
disableSslVerification |
boolean | false |
If true , disables SSL/TLS certificate verification for HTTPS connections. |
method |
string | "GET" |
HTTP method to use (e.g., "GET" , "POST" , "PUT" , "DELETE" ). |
headers |
object | {} |
Key/value map of HTTP headers to include with the request. |
data |
object | string | null | null |
Payload sent in the request body (typically for POST /PUT ). Can be an object or raw string. |
send() |
function | — | Sends the configured HTTP request. Returns a response object like { response_code: <int>, response_data: <object|string> } or throws on error. |
Here's an example of how you might use the HTTPClient
constructor to make an HTTP GET request:
// Create an instance of HTTPClient
var client = new HTTPClient();
// Set the URL to which the request will be sent
client.url = "http://time.jsontest.com/";
// Send the GET request
try {
var response = client.send();
// Log the response
log(response);
}
// Catch exceptions (4XX-5XX and all other errors)
catch (e) {
// Log the received exception.
log("Error: " + e.toString());
}
Result of response
{
"response_code": 200,
"response_data": {
"date": "07-30-2022",
"milliseconds_since_epoch": 1659147162342,
"time": "02:12:42 AM"
}
}
To use the HTTPClient
for making a POST request, you can follow a similar pattern as before, but this time you'll set the method
property to "POST" and provide data in the data
property. Here's an example:
// Create an instance of HTTPClient
var client = new HTTPClient();
// Set the URL to which the POST request will be sent
client.url = "https://example.com/api/post-endpoint";
// Set the HTTP method to POST
client.method = "POST";
// Set custom headers if needed (optional)
client.headers = {
"Content-Type": "application/json", // Assuming you're sending JSON data
"Authorization": "Bearer YOUR_ACCESS_TOKEN" // Add any authentication headers if required
};
// Disable SSL Verification
client.disableSslVerification = true;
// Define the data to be sent in the request body
client.data = {
username: "exampleUser",
password: "examplePassword"
};
// Send the POST request
try {
var post_response = client.send();
// Log the response
log(post_response);
}
// Catch exceptions (4XX-5XX and all other errors)
catch (e) {
// Log the received exception.
log("Error: " + e.toString());
}
Result of post_response
{
"response_code":200,
"response_data":"Thank you for this dump. I hope you have a lovely day!"
}
In this example, we've configured the HTTPClient
instance to make a POST request by setting the method
property to "POST." We've also specified custom headers (like Content-Type and Authorization) if they are required for your API. Finally, we've provided the data to be sent in the request body as an object in the data
property. Adjust the URL, headers, and data to match your specific use case and API requirements.
Result in Error / Debug logs
Logging
log(message)
For debugging, you can call the internal function log(message)
. To check the result of log()
, please use the Logs > Error/Debug logs
menu on the SpherAAA Dashboard.
MAC lookup
getVendor(mac)
MAC OUI stands for "Media Access Control Organizationally Unique Identifier." It is a 24-bit number that is used to uniquely identify the manufacturer of a network interface controller (NIC) in a device. The first three octets (24 bits) of a MAC address represent the OUI, which is assigned by the Institute of Electrical and Electronics Engineers (IEEE). The remaining three octets represent the device identifier, which is assigned by the manufacturer.
MAC OUI can be useful for network administrators in several ways:
-
Device identification: The MAC OUI allows network administrators to identify the manufacturer of a network device, which can be useful for determining the device's capabilities, compatibility with other devices, and support options.
-
Network troubleshooting: Knowing the manufacturer of a device can also help network administrators to troubleshoot issues with the device, as they can look up the device specifications and known issues to diagnose and resolve problems.
-
Inventory management: By knowing the manufacturer of a device, network administrators can keep track of their network inventory, which can be useful for managing and maintaining the network.
-
Security management: The MAC OUI can also be used to identify and track devices on the network, which can be useful for network security management. For example, if an unknown device is detected on the network, the MAC OUI can be used to identify the device and determine if it should be allowed on the network.
The MAC OUI can provide valuable information for network administrators in managing and maintaining their networks, as well as for ensuring the security and privacy of their network users.
SpherAAA has an internal function that allows the lookup of a device NIC vendor based on its MAC address.
getVendor(mac)
if a mac address was identified, returns the manufacturer name; otherwise returns private
.
Example
var vendor = getVendor(radius.request['Normalized-Mac']);
//Reject all devices manufactured by Apple.
if (vendor == "Apple, Inc.") {
fail("The use of Apple devices is prohibited.");
return;
}
Parallel processing
A function can be called in a new thread without delaying the current execution or response.
runParallel('function_name', delay_ms)
here:
-
function_name
: is a name of calling function -
delay_ms
: Delays execution of function in milliseconds. Default is 500ms
Example: This example was taken from Accounting PolicyLogic:
//
// Starting point
//
function start() {
//
// To avoid delaying the Accounting-Response, execute the Session update function in parallel.
// So first return Acct-Response
success();
//
// and then insert / update "sessions" collection
//
runParallel('acct()', 500);
}
//
// Update sessions collection.
//
function acct() {
// function: upsertEntry(collectionName, object, TTL, indexName, indexValue);
upsertEntry("sessions", radius.request, 86400, "Calling-Station-Id", radius.request['Calling-Station-Id']);
}
Parse Certificate fields
parseDN(dn)
Parse an X.509 Distinguished Name (DN) string into a structured object of attributes. Accepts a DN string (for example the value of radius.user.X509.SubjectDN
) and returns an object mapping attribute types (CN, OU, O, L, ST, C, etc.) to their values. If an attribute appears multiple times, its value will be an array preserving input order.
Example input location (note: certificate info is stored under radius.user.X509
):
// Example certificate stored after successful auth
radius.user = {
"Identity": "anonymous",
"Realm": "company.com",
"X509": {
"IssuerDN": "CN=localhost, OU=asdf, O=site.com-Root, L=Ashburn, ST=VA, C=US",
"SerialNumber": "645476476316797940957706362354238820466794377162",
"NotAfter": "Mon Jan 01 20:39:54 EDT 2026",
"NotBefore": "Sun Jan 01 20:39:54 EDT 2025",
"SubjectDN": "CN=anonymous@company.com, OU=1471-d4bd-4df7-91f4-29da, O=Company-Client, L=NewYork, ST=NY, C=US"
}
};
var subject = parseDN(radius.user.X509.SubjectDN);
// Example returned from "subject" object:
// {
// "CN": "anonymous@company.com",
// "OU": "1471-d4bd-4df7-91f4-29da",
// "O": "Company-Client",
// "L": "NewYork",
// "ST": "NY",
// "C": "US"
// }
// Access to CN:
var cn = subject.CN;
// Access to OU:
var ou = subject.OU;
Notes: - The function preserves attribute order when producing arrays for repeated attributes. - Attribute names are returned as standard short names (CN, OU, O, L, ST, C). If the input DN contains uncommon OIDs, the parser will expose them by their string representation when possible. - Use the safe-access pattern above when your flow may encounter multi-valued RDNs.
#### PKI Generate EAP-TLS Certificate
This example demonstrates how to use the `pkiGenCert` function to generate and issue a client certificate suitable for EAP-TLS authentication. The function is invoked with a single object argument that specifies the parameters for the certificate request.
**Request Object Parameters:**
| Key | Type | Description |
| -------------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| `ct` | String | The two-letter country code (e.g., "US"). |
| `st` | String | The state or province name (e.g., "NY"). |
| `city` | String | The city or locality name (e.g., "NewYork"). |
| `o` | String | The organization name (e.g., "Company"). |
| `ou` | String | The organizational unit name (e.g., "OrganisationUnit"). |
| `cn` | String | The common name for the certificate. For EAP-TLS, this is often an anonymous or user-specific identifier. |
| `days` | String | The number of days the certificate will be valid. |
| `passphrase` | String | A passphrase to protect the private key. A value of "nopass" indicates no passphrase. |
| `comment` | String | A descriptive comment for the certificate. |
| `email_send_as_file` | String | If set to a recipient's email address, the generated certificate will be sent to that address as an attachment. |
| `email_send_as_url` | String | If set to a recipient's email address, the generated certificate will be sent to that address as a download URL. |
| `ssid` | String | The SSID for which the certificate is intended. Can be set to a placeholder like "nossid" if not applicable. |
| `ca_id` | String | The unique identifier (From CA/SCEP Menu) of the Certificate Authority that will sign and issue the certificate. |
| `cert_type` | String | The desired output format for the certificate. Supported formats include `"pem"`, `"p12"`, and `"apple_mobileconfig"`. |
The `generateCert` function constructs a certificate request object with all the necessary details for the certificate, such as the subject's distinguished name (Country, State, City, Organization, etc.), validity period, and output format. Once the request object is defined, it's passed to the `pkiGenCert` function to initiate the certificate generation and delivery process.
Call generateCert(email) to build and submit a certificate request and deliver the generated certificate (or download link) to the specified email address.
```js
// generateCert(email)
// Build a certificate request object and call pkiGenCert() to generate and deliver the cert.
// email - recipient address to send the generated certificate as a file (if email_send_as_file is set).
function generateCert(email) {
var cert_request = {
// Subject fields
"ct": "US", // Country (2-letter code)
"st": "NY", // State or province
"city": "NewYork", // City / Locality
"o": "Company", // Organization
"ou": "OrganisationUnit", // Organizational Unit
"cn": "anonymous@company.com", // Common Name (often used for user identifier)
// Validity & protection
"days": "365", // Validity period in days
"passphrase": "nopass", // "nopass" = no private key passphrase
// Metadata / delivery
"comment": "EAP-TLS Client Cert", // Human-readable comment
"email_send_as_file": email, // If set to email addresss value, send a cert as an attachment
"email_send_as_url": false, // If set to email addresss value, send a download URL instead of attaching the file
// Certificate usage / CA / format
"ssid": "nossid", // Optional SSID tag for the cert (use "nossid" if not applicable)
"ca_id": "687aa36926d95d8920665d72",// CA certificate ID to sign the client cert
"cert_type": "apple_mobileconfig" // Output format: "pem", "p12", or "apple_mobileconfig"
};
// Submit the request to the PKI generator which will create and deliver the certificate.
pkiGenCert(cert_request);
}
Vault
To securely manage sensitive configuration data, this feature allows you to encrypt and store key-value pairs within a secure vault. You can create entries either through the Collections → Vault
interface or programmatically using the provided API.
This function encrypts and stores the provided key
and value
in the secure vault storage.
writeToVault(key, value, ttl, note)
-
ttl
- Time to Live for this data, in seconds -
note
- Comment for this data.
Example:
// Store OAuth access token in the vault.
writeToVault("access_token", "64a38d6ad29a848113e51e", 3600, "oauth access token");
readFromVault(key)
Retrieves and decrypts an encrypted value associated with the given key
from the secure vault storage in the database. Returns the decrypted value or null if not found.
Example:
var access_token = readFromVault("access_token");
// Returns 64a38d6ad29a848113e51e