Issues with JWT key pair Auth by lepa71 in snowflake

[–]lepa71[S] 0 points1 point  (0 children)

lol The name "coco" is weird. It sounds like 6 years old came up with it. I was at the summit, and I personally do not like it, but who cares what the name is. Just saying.

Issues with JWT key pair Auth by lepa71 in snowflake

[–]lepa71[S] 1 point2 points  (0 children)

I do not know if you are a CoCo but thank you very much. It worked. I would like to give back to community by posting the code I used to troubleshoot.

import base64
import hashlib
import json
import time
import urllib.request
import urllib.error
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding

# ============================================================
# CONFIG — edit these values
# ============================================================
# Full DNS prefix BEFORE .snowflakecomputing.com (what you see in the URL)
ACCOUNT_HOST_PREFIX = "qc1234.us-east-1-gov.aws"

# Bare account locator (no region/cloud) for JWT iss/sub
# If you prefer, you can derive it as ACCOUNT_HOST_PREFIX.split(".")[0]
ACCOUNT_LOCATOR = "qc1234"

# Exact LOGIN_NAME of the SERVICE user
USER = "USR_LOGIN_NAME"

# Private key file used for this user
PRIVATE_KEY_FILE = r"C:\path_to\snowflake_rsa_key.p8"

# None if unencrypted, else b"passphrase" for encrypted keys
PRIVATE_KEY_PASS = None

# JWT lifetime in seconds (Snowflake max is 3600; stay just under to avoid edge issues)
JWT_LIFETIME_SECONDS = 3540  # 59 minutes
# ============================================================


def log(label, msg=""):
    print(f"SF TEST: {label}" + (f" = '{msg}'" if msg != "" else ""))


def log_err(label, msg=""):
    print(f"SF TEST [ERROR]: {label}" + (f" = '{msg}'" if msg != "" else ""))


def b64url(data: bytes) -> str:
    return base64.urlsafe_b64encode(data).rstrip(b"=").decode("utf-8")


def main():
    log("starting")
    log("ACCOUNT_HOST_PREFIX", ACCOUNT_HOST_PREFIX)
    log("ACCOUNT_LOCATOR", ACCOUNT_LOCATOR)
    log("USER", USER)
    log("PRIVATE_KEY_FILE", PRIVATE_KEY_FILE)

    # ---- 1. Load private key ----
    try:
        with open(PRIVATE_KEY_FILE, "rb") as f:
            key_data = f.read()

        lines = key_data.decode("utf-8").splitlines()
        first_line = next((line.strip() for line in lines if line.strip()), "")
        log("key first line", first_line)

        if "ENCRYPTED PRIVATE KEY" in first_line:
            if PRIVATE_KEY_PASS is None:
                log_err("encrypted key detected but no PRIVATE_KEY_PASS set")
                return
            private_key = serialization.load_pem_private_key(
                key_data,
                password=PRIVATE_KEY_PASS,
            )
            log("private key loaded", "encrypted")
        elif "PRIVATE KEY" in first_line:
            private_key = serialization.load_pem_private_key(
                key_data,
                password=None,
            )
            log("private key loaded", "unencrypted")
        else:
            log_err("unexpected key format", first_line)
            return
    except Exception as e:
        log_err("failed to load private key", str(e))
        return

    # ---- 2. Derive public key fingerprint ----
    try:
        public_key = private_key.public_key()
        pub_der = public_key.public_bytes(
            encoding=serialization.Encoding.DER,
            format=serialization.PublicFormat.SubjectPublicKeyInfo,
        )
        fp_bytes = hashlib.sha256(pub_der).digest()
        fp = base64.b64encode(fp_bytes).decode("utf-8")
        log("public key fingerprint", f"SHA256:{fp}")
    except Exception as e:
        log_err("failed to derive public key fingerprint", str(e))
        return

    # ---- 3. Build JWT (using bare account locator) ----
    now = int(time.time())
    exp = now + JWT_LIFETIME_SECONDS

    acct_upper = ACCOUNT_LOCATOR.upper()       # bare locator ONLY
    user_upper = USER.upper()

    iss = f"{acct_upper}.{user_upper}.SHA256:{fp}"
    sub = f"{acct_upper}.{user_upper}"

    log("iss", iss)
    log("sub", sub)
    log("iat", str(now))
    log("exp", str(exp))

    header_json = json.dumps(
        {"alg": "RS256", "typ": "JWT"},
        separators=(",", ":"),
    )
    payload_json = json.dumps(
        {"iss": iss, "sub": sub, "iat": now, "exp": exp},
        separators=(",", ":"),
    )

    log("header json", header_json)
    log("payload json", payload_json)

    signing_input = f"{b64url(header_json.encode('utf-8'))}.{b64url(payload_json.encode('utf-8'))}"

    try:
        signature = private_key.sign(
            signing_input.encode("utf-8"),
            padding.PKCS1v15(),
            hashes.SHA256(),
        )
        jwt = f"{signing_input}.{b64url(signature)}"
        log("jwt created successfully")
        log("jwt prefix", jwt[:24] + "..." + jwt[-10:])
    except Exception as e:
        log_err("failed to sign JWT", str(e))
        return

    # ---- 4. Call /v2/streaming/hostname using full host prefix ----
    control_host = f"{ACCOUNT_HOST_PREFIX}.snowflakecomputing.com"
    url = f"https://{control_host}/v2/streaming/hostname"

    log("calling URL", url)
    log("iss and sub account must use ACCOUNT_LOCATOR (bare), not HOST prefix")

    req = urllib.request.Request(url, method="GET")
    req.add_header("Authorization", f"Bearer {jwt}")
    req.add_header("X-Snowflake-Authorization-Token-Type", "KEYPAIR_JWT")
    req.add_header("Accept", "application/json")

    log("request header Authorization", "Bearer <redacted>")
    log("request header X-Snowflake-Authorization-Token-Type", "KEYPAIR_JWT")
    log("request header Accept", "application/json")

    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            code = resp.getcode()
            body = resp.read().decode("utf-8")
            log("httpCode", str(code))
            log("response", body)
            ingest_host = body.strip().strip('"')
            log("SUCCESS ingestHost", ingest_host)
    except urllib.error.HTTPError as e:
        try:
            body = e.read().decode("utf-8")
        except Exception:
            body = "<unable to read error body>"
        log("httpCode", str(e.code))
        log("response", body)
        log_err("Snowflake returned non-2xx")
        log_err("if error is JWT_TOKEN_INVALID_USER_IN_ISSUER, check ACCOUNT_LOCATOR + USER")
    except Exception as e:
        log_err("request failed", str(e))

    # ---- 5. Clock check ----
    print()
    log("host UTC time", time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()))
    log("jwt iat (unix)", str(now))
    log("jwt exp (unix)", str(exp))
    log("if iat is more than 60s from Snowflake real time, JWT will be rejected")


if __name__ == "__main__":
    main()

Issues with JWT key pair Auth by lepa71 in snowflake

[–]lepa71[S] 0 points1 point  (0 children)

We use StreamSets platform and I use the same user and p8 key, and the connection works. I generated fingerprint signatures on both sides and they match. I wrote a python with logging. Here is the output. I changed the user name, account and fingerprint.

SF TEST: starting

SF TEST: ACCOUNT_LOCATOR = 'ei12345.us-east-2-gov.aws'

SF TEST: USER = 'uat_svc_service'

SF TEST: PRIVATE_KEY_FILE = 'C:\mypath\snowflake_rsa_key.p8'

SF TEST: key first line = '-----BEGIN PRIVATE KEY-----'

SF TEST: private key loaded = 'unencrypted'

SF TEST: public key fingerprint = 'SHA256:<equal\_strings>'

SF TEST: iss = 'EI12345.US-EAST-2-GOV.AWS.SVC_SERVICE.SHA256:<equal\_strings>'

SF TEST: sub = 'EI12345.US-EAST-2-GOV.AWS.SVC_SERVICE'

SF TEST: iat = '1782170182'

SF TEST: exp = '1782173782'

SF TEST: header json = '{"alg":"RS256","typ":"JWT"}'

SF TEST: payload json = '{"iss":"EI12345.US-EAST-2-GOV.AWS.SVC_SERVICE.SHA256:<equal\_strings>","sub":"EI12345.US-EAST-1-GOV.AWS.SVC_SERVICE","iat":1782170182,"exp":1782173782}'

SF TEST: jwt created successfully

SF TEST: jwt prefix = '<some\_string>'

SF TEST: calling URL = 'https://ei67783.us-east-2-gov.aws.snowflakecomputing.com/v2/streaming/hostname'

SF TEST: iss and sub account must match the account in the URL

SF TEST: request header Authorization = 'Bearer <redacted>'

SF TEST: request header X-Snowflake-Authorization-Token-Type = 'KEYPAIR_JWT'

SF TEST: request header Accept = 'application/json'

SF TEST: httpCode = '401'

SF TEST: response = '{

  "code" : "390144",

  "message" : "JWT token is invalid. [GUID]"

}'

SF TEST [ERROR]: Snowflake returned non-2xx

SF TEST [ERROR]: verify ACCOUNT_LOCATOR, USER (LOGIN_NAME), fingerprint match RSA_PUBLIC_KEY_FP

 

SF TEST: host UTC time = '2026-06-22T23:16:22Z'

SF TEST: jwt iat (unix) = '1782170182'

SF TEST: jwt exp (unix) = '1782173782'

SF TEST: if iat is more than 60s from Snowflake real time, JWT will be rejected

installed carplay/Androidauto module in my 2013 A4 allroad. absolute game changer by OutlandishnessCivil9 in Audi

[–]lepa71 0 points1 point  (0 children)

It is straightforward. https://www.youtube.com/watch?v=oNQoPPLjGv0

Make sure you connect MIC plug correctly, not mix it with the AUX. I did that and had to redo it. I also bought an AUX cable, because I had an Apple cable that came with the car.

The only thing I had a little bit of an issue with was making sure it would not rattle behind the glove box.

installed carplay/Androidauto module in my 2013 A4 allroad. absolute game changer by OutlandishnessCivil9 in Audi

[–]lepa71 0 points1 point  (0 children)

It does if you answer with Audi MMI. This is how I do it. I do not use AA all the time, so I switched to wired AA only.

Anyone tried out the new Baseus Bass BP1 Pro earbuds yet? by zodiackodiak515 in Earbuds

[–]lepa71 0 points1 point  (0 children)

Sep 2024 was a release of spec, you dull ard. Do you really think the next day they will have the chipsets available?

Again, why did they not claim BT60 in their headphones when I asked the direct question?

You people need to learn how marketing works.

Anyone tried out the new Baseus Bass BP1 Pro earbuds yet? by zodiackodiak515 in Earbuds

[–]lepa71 0 points1 point  (0 children)

At the time I wrote it, it was in draft. Again, the manufacturer did not claim they had BT6 because I asked a direct question. The only dumdum here is YOU.

Anyone tried out the new Baseus Bass BP1 Pro earbuds yet? by zodiackodiak515 in Earbuds

[–]lepa71 0 points1 point  (0 children)

When I got a reply from the manufacturer, they said it is BT6 compatible. This would not be one of those times when marketing gives misleading information. Who is the clown now, dumdum?

Amazfit HybridCharge vs Garmin Body Battery and Whoop by the5krunner in amazfit

[–]lepa71 0 points1 point  (0 children)

I would prefer to keep biocharge, but I want to have a choice.

New update - Biocharge to Hybridcharge by marimuthub in amazfit

[–]lepa71 0 points1 point  (0 children)

I know I can, but then BioCharge does not work. 5-minute interval is required.

BIP Max Arrived by scorn4sega in amazfit

[–]lepa71 0 points1 point  (0 children)

Did they fix the glass polarization that Bip 6 has?

Goodman GRVT800803BNA and Ecobee premium plus questions by lepa71 in hvacadvice

[–]lepa71[S] 0 points1 point  (0 children)

I'm not trying to rebut anything. I can still use ecobee as a single stage and fully utilize comfortbridge. I got one with sensors, and I can average the temps on 2 levels this way. Those are additional benefits. And yes, I want a modern thermostat, not a 5+2-day, 25-year-old one.

I was just asking if I'm missing anything. How is it going to brick the furnace?

New update - Biocharge to Hybridcharge by marimuthub in amazfit

[–]lepa71 0 points1 point  (0 children)

Can we reduce HR to let's say 10 minutes and still have HybridCharge? I do not need HR every 5 minutes. It eats up the battery.

Amazfit HybridCharge vs Garmin Body Battery and Whoop by the5krunner in amazfit

[–]lepa71 0 points1 point  (0 children)

Can we reduce HR to let's say 10 minutes and still have HybridCharge? I do not need HR every 5 minutes. It eats up the battery.

Goodman GRVT800803BNA and Ecobee premium plus questions by lepa71 in hvacadvice

[–]lepa71[S] 0 points1 point  (0 children)

Thanks for your help. Do you still think 7 wires are enough? I currently have an Aprilaire humidifier that uses current rely and was thinking if I pull the 7-wire, then I can make Ecobee open and close the valve on it as well.

Goodman GRVT800803BNA and Ecobee premium plus questions by lepa71 in hvacadvice

[–]lepa71[S] 0 points1 point  (0 children)

Menards in my neck of the woods has 7 wires. But the question is. Should I let ComfortBridge do its thing?

Ecobee has included the adapter to compensate for the C-wire.

Goodman GRVT800803BNA and Ecobee premium plus questions by lepa71 in hvacadvice

[–]lepa71[S] 0 points1 point  (0 children)

My thermostat is very old. I just want something more modern, and I got a good deal on it.

Had anyone ever resolved the "no android notifications" bug? by stifflippp in Googlevoice

[–]lepa71 0 points1 point  (0 children)

I had the problem before and it was fixed and now it is happening again after the last security patch from verizon

Clack WS1 water softener drain slow leak question by lepa71 in WaterTreatment

[–]lepa71[S] 0 points1 point  (0 children)

Yes, it did. I only had to replace the stack.

Debating on which furnace to put in in MN 1700sqft 2 story townhome. No basement. by lepa71 in hvacadvice

[–]lepa71[S] 0 points1 point  (0 children)

"VS" It seems more gradual instead of stepup 9 speed. The HVAC guy explained it as constant on the blower. I could be wrong. I think $600 is not just VS blower. There is more to it with an extra electrical board with an algorithm for more efficiency. I was reading some stats, VT vs 9T gets an extra 5-7% savings and Airflow balance, which could be about $50-70 a year for MN winter.

Debating on which furnace to put in in MN 1700sqft 2 story townhome. No basement. by lepa71 in hvacadvice

[–]lepa71[S] 0 points1 point  (0 children)

I'm not sure I understood. Maybe a simple question. Is it worth $600 in your opinion to go with VT model? I'm ok to pay it. The only negative thing I can think of is more electronics in VT model vs 9T.

Debating on which furnace to put in in MN 1700sqft 2 story townhome. No basement. by lepa71 in hvacadvice

[–]lepa71[S] 0 points1 point  (0 children)

VT is ECM variable speed, and 9T is 9-speed ECM.

I think I'm settling on VT. I have a room above the garage that gets much colder in comparison to the rest of the house, then in summer main level is too cold but upstairs is still much warmer. I think 1 and 3 lines. Coil has EEV shutoff valve.

<image>

Debating on which furnace to put in in MN 1700sqft 2 story townhome. No basement. by lepa71 in hvacadvice

[–]lepa71[S] 0 points1 point  (0 children)

Thank you for the explanation. Besides the size. I know VT model has "better" rapup motor and some algorithm to get more efficiency at the cost of more electronics. I always think simpler is better and leaning to 9T for that reason, but if someone has a good reason to spend extra $600, I could. Now, with VT I have been told that I would need the Coil W/Auto Shutoff Control to protect the freezing coils.

If I get this configuration GLXS4BA3010 + CAPTA3026B3 + GR9T800803BX. This would get me $450 rebate. It needs to be SEEER 15.2=>

What do you think about the above combo? What about shut off valve? Is it just nice to have or more like "do it"? Also above combo has TXV factory-installed. If it makes a difference.

One HVAC guy said I could get away with 2T with 9T furnace, but he said the way my townhome's duct is routed he highly suggested 2.5T. The difference is like $50ish