How do you attach credentials to a repository declaration in Gradle without hardcoding secrets in the build script?
answer
- credentials {} inside maven/ivy
- never hardcode in build script
- ~/.gradle/gradle.properties / env
- named repo -> <name>Username/Password
- providers for config-cache safety
basics
~10 sAdd a credentials {} block to the repository and read username/password from gradle.properties or the environment instead of inlining them. With a named repo, Gradle can also auto-map <name>Username/<name>Password properties.
solid answer
~50 sA private repository needs auth, declared with a `credentials {}` block inside `maven {}`/`ivy {}`. The cardinal rule is **never** put literal secrets in the versioned build script. Two idiomatic options: (1) pull values from properties or env, e.g. `credentials { username = providers.gradleProperty("repoUser").get(); password = providers.environmentVariable("REPO_TOKEN").get() }`, keeping the real values in `~/.gradle/gradle.properties` (outside the repo) or CI secrets; or (2) name the repository and let Gradle auto-resolve `<name>Username`/`<name>Password` properties — declaring `credentials(PasswordCredentials::class)` on a repo named `corpNexus` makes Gradle read `corpNexusUsername`/`corpNexusPassword`. Gradle also supports `HttpHeaderCredentials` (for token headers) and `AwsCredentials` (for S3-backed repos). Using the `Provider`-based property accessors lets Gradle defer reading the secret until the repo is actually used and integrates with configuration cache. The deeper mechanics of authentication schemes belong to authenticated-repository handling; at the declaration level the point is: declare `credentials {}`, source secrets externally, prefer named-repo auto-mapping or providers.
code
kotlin · 11 linesrepositories {
maven {
name = "corpNexus" // -> corpNexusUsername / corpNexusPassword
url = uri("https://nexus.corp/repo")
credentials(PasswordCredentials::class) // auto-mapped from gradle.properties
}
}
// ~/.gradle/gradle.properties (NOT committed):
// corpNexusUsername=ci-bot
// corpNexusPassword=ghp_xxxgo deeper
Know that private repos need a credentials {} block and secrets shouldn't be inline.
Source secrets from gradle.properties/env; know the named-repo auto-mapping convention.
Choose credential types (password/header/AWS), use Provider APIs for config-cache safety, enforce HTTPS.
Define org-wide secret management (CI vaults, token rotation) and ban committed credentials via policy/scanning.
## The problem Private Maven/Ivy repos require authentication. You must declare it, but the build script is checked into version control — so the secret must come from **outside** the script. ## credentials {} block The basic form attaches a username/password to a repository: ```kotlin repositories { maven { url = uri("https://nexus.corp/repository/maven-releases/") credentials { username = providers.gradleProperty("corpUser").get() password = providers.environmentVariable("CORP_TOKEN").get() } } } ``` Real values live in `~/.gradle/gradle.properties` (user-global, **not** committed) or are injected as environment variables / CI secrets. ## Named-repository auto-mapping If you give the repository a `name` and use the typed credentials form, Gradle automatically reads `<name>Username` and `<name>Password` from the available properties: ```kotlin repositories { maven { name = "corpNexus" url = uri("https://nexus.corp/repo") credentials(PasswordCredentials::class) // reads corpNexusUsername / corpNexusPassword } } ``` This is the cleanest pattern: no secret text in the script at all, just a naming convention. ## Credential types - `PasswordCredentials` — username + password (HTTP Basic). - `HttpHeaderCredentials` — a custom header, e.g. a bearer/PAT token (`name = "Authorization"`, `value = "Bearer ..."`), paired with an auth scheme. - `AwsCredentials` — for `s3://` repositories. ## Providers and laziness Using `providers.gradleProperty(...)` / `providers.environmentVariable(...)` returns a **Provider**, so Gradle can defer reading the secret until the repository is actually queried, and it plays well with the **configuration cache** (a literal `System.getenv(...)` at configuration time can invalidate or leak into the cache). Prefer the provider APIs. ## Hygiene rules - Never commit secrets; keep them in `~/.gradle/gradle.properties` or CI secret stores. - Always use HTTPS for credentialed repos (Gradle warns/forbids plaintext HTTP auth unless explicitly allowed). - Prefer tokens over passwords where the server supports them. (How authentication schemes are negotiated and preemptive auth are deeper authenticated-repository topics; here the focus is wiring credentials into the *declaration* safely.)
- Where should the actual secret values live?Outside version control: `~/.gradle/gradle.properties` (user-global), environment variables, or a CI secret store — never in the committed build script.
- How does naming a repository simplify credentials?With `name = "corpNexus"` and `credentials(PasswordCredentials::class)`, Gradle auto-reads `corpNexusUsername`/`corpNexusPassword` from properties, so no secret text appears in the script.
- Why prefer providers.environmentVariable over System.getenv for a credential?Providers are lazy and configuration-cache friendly; reading env eagerly at configuration time can break or pollute the configuration cache.
saying these in an interview costs you the question
- Hardcoding a username/password directly in build.gradle.kts.
- Committing secrets to the project's gradle.properties.
- Using plain HTTP for an authenticated repository.