# Jenkins

> Publish from Jenkins with the OpenID Connect Provider plugin and a trust policy.

Source: https://docs.telesphorepo.com/publishing/jenkins/

Jenkins can publish without a stored secret. The **OpenID Connect Provider** plugin gives each job an identity token. Telesphorepo trades it for a [publish session](/publishing/overview/).

## Set up

1. Install the **OpenID Connect Provider** plugin in Jenkins.
2. In Jenkins, add a credential of the kind “OpenID Connect id token”. Set its audience to the URL of your Telesphorepo server, for example `https://repo.acme.com`. Give it the ID `telesphorepo-oidc`.
3. An admin opens the **Trust policies** page and picks the Jenkins preset. The issuer is the Jenkins URL followed by `/oidc`, for example `https://jenkins.acme.com/oidc`.
4. Add at least one claim that limits which jobs may publish. List the repositories that the policy may publish to.
5. Leave the audience empty, or set it to the same text as in the Jenkins credential. Empty means the `base_url` of the server.

See [Trust policies](/security/trust-policies/) for all fields.

## Publish with curl

```groovy title="Jenkinsfile"
withCredentials([string(credentialsId: 'telesphorepo-oidc', variable: 'OIDC')]) {
  sh '''
    SESSION=$(curl -sSf https://repo.acme.com/api/publish/sessions/oidc \
      -H 'Content-Type: application/json' \
      -d "{\\"token\\":\\"$OIDC\\",\\"repo\\":\\"releases\\"}")
    TOKEN=$(echo "$SESSION" | jq -r .token)
    curl -sSf -u "ci:$TOKEN" -T app-1.0.jar \
      https://repo.acme.com/maven/releases/com/acme/app/1.0/app-1.0.jar
    curl -sSf -X DELETE -u "ci:$TOKEN" \
      "https://repo.acme.com/api/publish/sessions/$(echo "$SESSION" | jq -r .id)"
  '''
}
```

The agent needs `curl` and `jq`.

## Publish with the plugin or extension

Both clients read the token from an environment variable.

1. In the Gradle settings, set `oidcTokenEnv`. See [Gradle plugin](/publishing/gradle-plugin/).

   ```kotlin
   telesphorepo {
       url = "https://repo.acme.com"
       oidcTokenEnv = "OIDC"
   }
   ```

   For Maven, pass `-Dtelesphorepo.oidcTokenEnv=OIDC`. See [Maven extension](/publishing/maven-extension/).

2. Run the build inside `withCredentials`, so that the variable is set:

   ```groovy title="Jenkinsfile"
   withCredentials([string(credentialsId: 'telesphorepo-oidc', variable: 'OIDC')]) {
     sh './gradlew publish'
   }
   ```

## When the server cannot reach Jenkins

The server finds the signing keys of the issuer through discovery. If Jenkins is on a private network, the server cannot do this. Paste the keys into the trust policy instead.

1. Download the JWKS of Jenkins from the `jwks_uri` in `<jenkins url>/oidc/.well-known/openid-configuration`.
2. Paste the JSON into the **JWKS** field of the trust policy.
3. Save. The server checks the pasted keys when you save and uses them instead of discovery.

Update the pasted JWKS when Jenkins rotates its keys.

## Gotchas

- The `iss` claim of the token must equal the issuer of the policy exactly. A different host name or a missing `/oidc` fails the match.
- The `aud` claim must equal the audience of the policy. A mismatch fails the exchange.
- The server accepts each token once and only if it is at most 10 minutes old. Use a fresh token for each exchange.
- The server accepts RS, ES and PS signatures (256, 384, 512 bits) and EdDSA.
- If you edit or disable a policy, the server ends its open sessions.
