Integrations
MAC Address Bypass (MAB) API
25 min
overview the nile mac address bypass (mab) api allows you to programmatically retrieve network metadata (segments, sites, zones, etc ) and update a device’s mac address authentication status it can be used to build automated mab approval workflows with third party tools mab is most commonly applied to iot, headless devices, or other clients that cannot support 802 1x authentication the mac address bypass (mab) api is offered as is and is not included in nile’s supported feature set please note that nile support does not offer troubleshooting or assistance for this api authentication all requests require an api key header format obtain your api key in the nile portal creating an api key log into nile portal using an admin account click on the global settings icon on the left side click on security tab on api key management, click on the “add key ” button to generate a new api token fill add key info name key name (example “nile mab api” ) duration (days) token key validity, the maximum is 1 year (365 days) workflow select the workflow that we want to generate a key for for mab onboarding, we select ‘ mab onboarding api ’ read only select ‘read only’ to enable the api for read only access by default, the api key permits read/write operations however, if you intend to update mab entries, such as approving or denying mac addresses in specific segments, it is advised not to enable 'read only' access "click on save to save the config click save to save the api key after saving the configuration, a json file containing key information will automatically download to your computer 🔒 note please keep this information in a secure location for security reasons, this file cannot be downloaded again if the key is lost or compromised, it must be revoked, and a new key must be created quick start step 1 export your api key 2\ list available segments note on formatting by default, curl prints json as one long line for readability, pipe through jq if jq is not installed macos brew install jq debian/ubuntu sudo apt get install jq windows powershell | convertfrom json | convertto json depth 8 sample output (pretty printed with jq, truncated) 3\ get client config for a device (by mac address) sample output (truncated, pretty printed with jq, anonymized) endpoints for readability, long ids are truncated with in real responses you will see full uuid values segments retrieve tenant segments sample output (truncated) sites retrieve site information sample output (truncated) buildings retrieve buildings sample output (truncated) floors retrieve floors sample output (truncated) zones retrieve zones sample output (truncated) client configs — list returns json data that includes a list of (device) client configurations within a given tenant multiple attributes can be used for filtering, including tenantid macaddress locktoport geo scope ids (e g , site id, building id, floor id, etc ) sample execution and output (truncated) client configs — update use this endpoint to update a device’s mac address authentication state required fields (per mac) id — the full id returned by client configs list (tenant + mac) macaddress — the device’s mac address segmentid — the id of the segment to assign state — new state value description — optional free text note valid state values state meaning typical use auth ok device approved approve iot/headless auth denied device denied access block rogue or unwanted waiting for approval (if shown) pending admin action default for new devices single device example create mac json run the patch bulk update (multiple devices) you can update more than one mac in a single request by adding multiple objects to the macslist array response codes 204 no content → update succeeded (most common) errors return json body with code and message best practices always get the device first using client configs list to confirm the id and segmentid before patching use a json file ( d @mac json) rather than inline json to avoid quoting issues example scripts \#!/usr/bin/env python3 \# usage export nile api key= python3 mab approve py \<macaddress> \<segmentid> import os, sys, json, requests base url = "https //u1 nile global cloud/api/v1" api key = os environ get("nile api key") if not api key sys stderr write("❌ missing nile api key environment variable\n") sys exit(1) def h() return { "authorization" f"bearer {api key}", "accept" "application/json", "content type" "application/json", } def get client config(mac str) url = f"{base url}/client configs list?filter=macaddress=={mac}" r = requests get(url, headers=h(), timeout=30) r raise for status() data = r json() if isinstance(data, list) return data\[0] if data else none if isinstance(data, dict) and isinstance(data get("data"), list) return data\["data"]\[0] if data\["data"] else none return none def approve mac(cfg id str, mac str, segment id str) body = { "macslist" \[ {"id" cfg id, "macaddress" mac, "segmentid" segment id, "state" "auth ok"} ] } r = requests patch(f"{base url}/client configs", headers=h(), json=body, timeout=30) if r status code not in (200, 204) raise runtimeerror(f"patch failed ({r status code}) {r text}") def main() if len(sys argv) != 3 sys stderr write("usage nile api key= python3 mab approve py \<macaddress> \<segmentid>\n") sys exit(1) mac, segment id = sys argv\[1], sys argv\[2] row = get client config(mac) if not row sys stderr write(f"❌ no client config found for mac {mac}\n") sys exit(1) \# normalize possible shapes cfg = row\ get("clientconfig") or row\ get("attributes") or row cfg id = cfg get("id") if not cfg id sys stderr write("❌ missing id in client config response\n") sys exit(1) approve mac(cfg id, mac, segment id) print(f"✅ approved {mac} (id={cfg id}) into segment {segment id}") if name == " main " main()// this script // 1 gets the client config for a mac to retrieve its id // 2 patches the client config to set state=auth ok and assign it to the target segment // usage node mab approve native js \<macaddress> \<segmentid> const https = require("https"); const base = "u1 nile global cloud"; const api key = process env nile api key; if (!api key) { console error("❌ missing nile api key environment variable"); process exit(1); } const mac = process argv\[2]; const segmentid = process argv\[3]; if (!mac || !segmentid) { console error("usage nile api key= node mab approve native js \<macaddress> \<segmentid>"); process exit(1); } // helper to run https requests function dorequest(options, body = null) { return new promise((resolve, reject) => { const req = https request(options, res => { let data = ""; res on("data", chunk => (data += chunk)); res on("end", () => resolve({ status res statuscode, data })); }); req on("error", reject); if (body) req write(body); req end(); }); } // get client config to pull the id async function getclientconfig(mac) { const options = { hostname base, port 443, path `/api/v1/client configs list?filter=macaddress==${encodeuricomponent(mac)}`, method "get", headers { "authorization" `bearer ${api key}`, "accept" "application/json" } }; const { status, data } = await dorequest(options); if (status !== 200) throw new error(`get failed (${status}) ${data}`); let parsed; try { parsed = json parse(data); } catch { throw new error(`failed to parse get response ${data}`); } if (array isarray(parsed) && parsed length > 0) return parsed\[0]; if (parsed data && array isarray(parsed data) && parsed data length > 0) return parsed data\[0]; throw new error(`no client config found for mac ${mac}`); } // patch client config (approve into target segment) async function approvemac(id, macaddress, segmentid) { const payload = json stringify({ macslist \[{ id, macaddress, segmentid, state "auth ok" }] }); const options = { hostname base, port 443, path "/api/v1/client configs", method "patch", headers { "authorization" `bearer ${api key}`, "accept" "application/json", "content type" "application/json", "content length" buffer bytelength(payload) } }; const { status, data } = await dorequest(options, payload); if (!\[200, 204] includes(status)) { throw new error(`patch failed (${status}) ${data}`); } } (async () => { try { // step 1 get to pull id const row = await getclientconfig(mac); const cfg = row\ clientconfig || row\ attributes || row; const id = cfg id; if (!id) throw new error("missing id in client config response"); // step 2 patch into specified segment await approvemac(id, mac, segmentid); console log(`✅ approved ${mac} (id=${id}) into segment ${segmentid}`); } catch (e) { console error("❌ error ", e message || e); process exit(1); } })();# usage \# $env\ nile api key="your token" \# win $env\ nile api key="your token" \# \mab approve ps1 mac "64 62 66 21\ c2 04" segmentid "\<segmentid>" \# macos pwsh /mab approve ps1 mac "\<macaddress>" segmentid "\<segmentid>" param( \[parameter(mandatory = $true)]\[string]$mac, \[parameter(mandatory = $true)]\[string]$segmentid ) $apikey = $env\ nile api key if ( not $apikey) { write error "missing nile api key environment variable"; exit 1 } $base = "https //u1 nile global cloud/api/v1" $headers = @{ "authorization" = "bearer $apikey" "accept" = "application/json" "content type" = "application/json" } function get clientconfig { param(\[string]$macaddr) $url = "$base/client configs list?filter=macaddress==$macaddr" $resp = invoke restmethod headers $headers uri $url method get if ($resp is \[system array]) { if ($resp length gt 0) { return $resp\[0] } else { return $null } } elseif ($resp data and $resp data count gt 0) { return $resp data\[0] } else { return $null } } function approve mac { param(\[string]$cfgid, \[string]$macaddr, \[string]$segid) $body = @{ macslist = @( @{ id = $cfgid macaddress = $macaddr segmentid = $segid state = "auth ok" } ) } | convertto json depth 5 \# invoke restmethod returns $null for 204 no content; that's ok try { $null = invoke restmethod headers $headers uri "$base/client configs" method patch body $body } catch { throw "patch failed $($ exception message)" } } $row = get clientconfig macaddr $mac if ( not $row) { write error "no client config found for $mac"; exit 1 } $cfg = if ($row\ clientconfig) { $row\ clientconfig } elseif ($row\ attributes) { $row\ attributes } else { $row } $cfgid = $cfg id if ( not $cfgid) { write error "missing id in client config response"; exit 1 } approve mac cfgid $cfgid macaddr $mac segid $segmentid write host "✅ approved $mac (id=$cfgid) into segment $segmentid"