v0.14 is out: a mobile auth pack for Swift/iOS and Android, catching insecure token storage, cleartext traffic, and OAuth in embedded WebViews. Read more →
HIGH AI PREVALENCE: HIGH auth.kotlin.secret.hardcoded-jwt-secret

A JWT signing key is built from a hard-coded string literal (Algorithm.HMAC256("...")).

Why AI tools produce this: AI coding tools generate this anti-pattern by default, it appears in a large share of AI-written auth code.

Why this matters

This key both signs and verifies every token: committed to source control it is one search away from compromise, letting an attacker forge tokens for any user or role (CWE-798). This is a common AI-generated mistake: a literal secret is inlined to make the Ktor/java-jwt sample "just work" and is never externalized.

Load the key from configuration or a secret store instead, e.g. Algorithm.HMAC256(System.getenv("JWT_SECRET")) or Algorithm.HMAC256(environment.config.property("jwt.secret").getString()), and rotate any secret that has already been checked in.

VULNERABLE
vulnerable.kt
import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm

fun signer(): Algorithm {
    // ruleid: auth.kotlin.secret.hardcoded-jwt-secret
    return Algorithm.HMAC256("s3cr3t-signing-key-do-not-share")
}

fun strongSigner(): Algorithm {
    // ruleid: auth.kotlin.secret.hardcoded-jwt-secret
    return Algorithm.HMAC512("another-inlined-super-secret-value")
}
SAFE
safe.kt
import com.auth0.jwt.algorithms.Algorithm
import io.ktor.server.application.*

fun signerFromEnv(): Algorithm {
    return Algorithm.HMAC256(System.getenv("JWT_SECRET"))
}

fun signerFromConfig(app: Application): Algorithm {
    val secret = app.environment.config.property("jwt.secret").getString()
    return Algorithm.HMAC256(secret)
}

fun placeholderIsIgnored(): Algorithm {
    // Documentation placeholder, not a real secret.
    return Algorithm.HMAC256("changeme")
}

Suppressing this rule

If a finding is a genuine false positive, scope the suppression to the exact line and leave a reason, never disable the rule project-wide. Disable directives are line-scoped by design.

// oauthlint-disable-next-line auth.kotlin.secret.hardcoded-jwt-secret -- <reason>

References

https://github.com/auth0/java-jwt ↗https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html ↗https://cwe.mitre.org/data/definitions/798.html ↗