0

Obtain and cache a ServiceNow OAuth2 access token

by
Published Apr 19, 2026

Authenticates against a ServiceNow instance using OAuth2 ROPC flow. The token is cached in a Windmill state resource (f/ServiceNow/snow_token_cache) and reused until it is within 60 seconds of expiry (default token lifetime is 30 minutes), minimising redundant auth calls across scripts in the same workspace. Run standalone to verify credentials and warm the cache, or import get_token as a shared auth helper in other ServiceNow scripts. Inputs: snow — ServiceNow resource (instance_url, client_id, client_secret, username, password)

Script servicenow
  • Submitted by elib3n379 Python3
    Created 51 days ago
    1
    
    
    2
    import time
    3
    import requests
    4
    from typing import TypedDict
    5
    
    
    6
    try:
    7
        import wmill
    8
        _WMILL_AVAILABLE = True
    9
    except ImportError:
    10
        _WMILL_AVAILABLE = False
    11
    
    
    12
    TOKEN_CACHE_PATH = "f/ServiceNow/snow_token_cache"
    13
    TOKEN_EXPIRY_BUFFER_SECS = 60
    14
    
    
    15
    
    
    16
    class servicenow(TypedDict):
    17
        instance_url: str
    18
        client_id: str
    19
        client_secret: str
    20
        username: str
    21
        password: str
    22
    
    
    23
    
    
    24
    def get_token(snow: servicenow) -> str:
    25
        """
    26
        Returns a valid ServiceNow access token.
    27
        Caches the token in f/ServiceNow/snow_token_cache and reuses it until
    28
        it is within 60s of expiry (default lifetime is 30 minutes).
    29
        Uses OAuth2 Resource Owner Password Credentials grant.
    30
        """
    31
        if _WMILL_AVAILABLE:
    32
            try:
    33
                cached = wmill.get_resource(TOKEN_CACHE_PATH)
    34
                if (
    35
                    isinstance(cached, dict)
    36
                    and cached.get("expires_at", 0) > time.time() + TOKEN_EXPIRY_BUFFER_SECS
    37
                ):
    38
                    return cached["token"]
    39
            except Exception:
    40
                pass
    41
    
    
    42
        resp = requests.post(
    43
            f"{snow['instance_url'].rstrip('/')}/oauth_token.do",
    44
            data={
    45
                "grant_type": "password",
    46
                "client_id": snow["client_id"],
    47
                "client_secret": snow["client_secret"],
    48
                "username": snow["username"],
    49
                "password": snow["password"],
    50
            },
    51
            headers={"Content-Type": "application/x-www-form-urlencoded"},
    52
            timeout=15,
    53
        )
    54
        resp.raise_for_status()
    55
        data = resp.json()
    56
    
    
    57
        if "error" in data:
    58
            raise RuntimeError(f"ServiceNow OAuth error: {data['error']} — {data.get('error_description', '')}")
    59
    
    
    60
        token = data["access_token"]
    61
        expires_in = data.get("expires_in", 1800)
    62
    
    
    63
        if _WMILL_AVAILABLE:
    64
            try:
    65
                wmill.set_resource(
    66
                    path=TOKEN_CACHE_PATH,
    67
                    value={"token": token, "expires_at": time.time() + expires_in},
    68
                    resource_type="state",
    69
                )
    70
            except Exception:
    71
                pass
    72
    
    
    73
        return token
    74
    
    
    75
    
    
    76
    def main(snow: servicenow) -> str:
    77
        """Verify credentials and warm the token cache. Safe to run standalone."""
    78
        token = get_token(snow)
    79
        print(f"Token obtained successfully (prefix: {token[:10]}...)")
    80
        print(f"Cached at: {TOKEN_CACHE_PATH}")
    81
        return "OK"
    82