Skip to content

chore: update sttp to v4 #577

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 39 additions & 51 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,42 +27,36 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
scala: [2.12.19, 2.13.13, 3.3.3]
java: [graalvm-ce-java11@20.3.0]
scala: [2.12.20, 2.13.16, 3.3.5]
java: [zulu@11]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout current branch (full)
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Java and Scala
uses: olafurpg/setup-scala@v13
- name: Setup Java (zulu@11)
if: matrix.java == 'zulu@11'
uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}
distribution: zulu
java-version: 11
cache: sbt

- name: Cache sbt
uses: actions/cache@v2
with:
path: |
~/.sbt
~/.ivy2/cache
~/.coursier/cache/v1
~/.cache/coursier/v1
~/AppData/Local/Coursier/Cache/v1
~/Library/Caches/Coursier/v1
key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }}
- name: Setup sbt
uses: sbt/setup-sbt@v1

- name: Check that workflows are up to date
run: sbt ++${{ matrix.scala }} githubWorkflowCheck
run: sbt '++ ${{ matrix.scala }}' githubWorkflowCheck

- run: sbt ++${{ matrix.scala }} test docs/mdoc mimaReportBinaryIssues
- run: sbt '++ ${{ matrix.scala }}' test docs/mdoc mimaReportBinaryIssues

- name: Compress target directories
run: tar cf targets.tar oauth2-jsoniter/jvm/target oauth2/js/target oauth2-cache/js/target oauth2-cache-ce2/target oauth2-cache-zio/target oauth2-jsoniter/js/target target oauth2-cache-scalacache/target mdoc/target oauth2-circe/jvm/target oauth2-cache-cats/target oauth2-cache-future/jvm/target oauth2-circe/js/target oauth2-cache/jvm/target oauth2-cache-future/js/target oauth2/jvm/target project/target

- name: Upload target directories
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: target-${{ matrix.os }}-${{ matrix.scala }}-${{ matrix.java }}
path: targets.tar
Expand All @@ -74,62 +68,56 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest]
scala: [2.13.13]
java: [graalvm-ce-java11@20.3.0]
scala: [2.13.16]
java: [zulu@11]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout current branch (full)
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Java and Scala
uses: olafurpg/setup-scala@v13
- name: Setup Java (zulu@11)
if: matrix.java == 'zulu@11'
uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java }}
distribution: zulu
java-version: 11
cache: sbt

- name: Cache sbt
uses: actions/cache@v2
with:
path: |
~/.sbt
~/.ivy2/cache
~/.coursier/cache/v1
~/.cache/coursier/v1
~/AppData/Local/Coursier/Cache/v1
~/Library/Caches/Coursier/v1
key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }}

- name: Download target directories (2.12.19)
uses: actions/download-artifact@v2
- name: Setup sbt
uses: sbt/setup-sbt@v1

- name: Download target directories (2.12.20)
uses: actions/download-artifact@v4
with:
name: target-${{ matrix.os }}-2.12.19-${{ matrix.java }}
name: target-${{ matrix.os }}-2.12.20-${{ matrix.java }}

- name: Inflate target directories (2.12.19)
- name: Inflate target directories (2.12.20)
run: |
tar xf targets.tar
rm targets.tar

- name: Download target directories (2.13.13)
uses: actions/download-artifact@v2
- name: Download target directories (2.13.16)
uses: actions/download-artifact@v4
with:
name: target-${{ matrix.os }}-2.13.13-${{ matrix.java }}
name: target-${{ matrix.os }}-2.13.16-${{ matrix.java }}

- name: Inflate target directories (2.13.13)
- name: Inflate target directories (2.13.16)
run: |
tar xf targets.tar
rm targets.tar

- name: Download target directories (3.3.3)
uses: actions/download-artifact@v2
- name: Download target directories (3.3.5)
uses: actions/download-artifact@v4
with:
name: target-${{ matrix.os }}-3.3.3-${{ matrix.java }}
name: target-${{ matrix.os }}-3.3.5-${{ matrix.java }}

- name: Inflate target directories (3.3.3)
- name: Inflate target directories (3.3.5)
run: |
tar xf targets.tar
rm targets.tar

- uses: olafurpg/setup-gpg@v3

- run: sbt ++${{ matrix.scala }} ci-release
- run: sbt ci-release
3 changes: 2 additions & 1 deletion .github/workflows/clean.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Delete artifacts
shell: bash {0}
run: |
# Customize those three lines with your repository and credentials:
REPO=${GITHUB_API_URL}/repos/${{ github.repository }}
Expand All @@ -25,7 +26,7 @@ jobs:
ghapi() { curl --silent --location --user _:$GITHUB_TOKEN "$@"; }

# A temporary file which receives HTTP response headers.
TMPFILE=/tmp/tmp.$$
TMPFILE=$(mktemp)

# An associative array, key: artifact name, value: number of artifacts of that name.
declare -A ARTCOUNT
Expand Down
14 changes: 6 additions & 8 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,13 @@ inThisBuild(

def crossPlugin(x: sbt.librarymanagement.ModuleID) = compilerPlugin(x.cross(CrossVersion.full))

val Scala212 = "2.12.19"
val Scala213 = "2.13.13"
val Scala3 = "3.3.3"

val GraalVM11 = "graalvm-ce-java11@20.3.0"
val Scala212 = "2.12.20"
val Scala213 = "2.13.16"
val Scala3 = "3.3.5"

ThisBuild / scalaVersion := Scala213
ThisBuild / crossScalaVersions := Seq(Scala212, Scala213, Scala3)
ThisBuild / githubWorkflowJavaVersions := Seq(GraalVM11)
ThisBuild / githubWorkflowJavaVersions := Seq(JavaSpec.zulu("11"))
ThisBuild / githubWorkflowBuild := Seq(
WorkflowStep.Sbt(List("test", "docs/mdoc", "mimaReportBinaryIssues"))
) // NOTE those run separately for every ScalaVersion in `crossScalaVersions`
Expand Down Expand Up @@ -55,7 +53,7 @@ val Versions = new {
val jsoniter = "2.30.7"
val monix = "3.4.1"
val scalaTest = "3.2.19"
val sttp = "3.9.8"
val sttp = "4.0.3"
val refined = "0.10.3"
val scalaCache = "1.0.0-M6"
}
Expand Down Expand Up @@ -88,7 +86,7 @@ lazy val oauth2 = crossProject(JSPlatform, JVMPlatform)
.settings(
name := "sttp-oauth2",
libraryDependencies ++= Seq(
"com.softwaremill.sttp.client3" %%% "core" % Versions.sttp,
"com.softwaremill.sttp.client4" %%% "core" % Versions.sttp,
"org.typelevel" %%% "cats-core" % Versions.catsCore,
"eu.timepit" %%% "refined" % Versions.refined,
"org.scalatest" %%% "scalatest" % Versions.scalaTest % Test
Expand Down
6 changes: 3 additions & 3 deletions docs/client-credentials.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ CachingAccessTokenProvider.refCacheInstance[IO](delegate)

## `sttp-oauth2` backends

`SttpOauth2ClientCredentialsBackend` is a `SttpBackend` which sends auth bearer headers for every `http` call performed with it using provided `AccessTokenProvider`.
`SttpOauth2ClientCredentialsBackend` is a `GenericBackend` which sends auth bearer headers for every `http` call performed with it using provided `AccessTokenProvider`.


```scala
val scope: Option[Scope] = Some("scope") // backend will use defined scope for all requests
val backend: SttpBackend[IO, Any] = SttpOauth2ClientCredentialsBackend[IO, Any](tokenUrl, clientId, clientSecret)(scope)(delegateBackend)
val backend: GenericBackend[IO, Any] = SttpOauth2ClientCredentialsBackend[IO, Any](tokenUrl, clientId, clientSecret)(scope)(delegateBackend)
backend.send(request) // this will add header: Authorization: Bearer {token}

```

In order to cache tokens, use one of the `AccessTokenProviders` described in Caching section.
In order to cache tokens, use one of the `AccessTokenProviders` described in Caching section.
20 changes: 10 additions & 10 deletions docs/migrating.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,48 +59,48 @@ If you were instantiating `AuthorizationCodeProvider` or using `AuthorizationCod

## [v0.14.0](https://github.com/polyvariant/sttp-oauth2/releases/tag/v0.14.0)

Due to Scala 3 support `Scope.refine` Refined macro has been removed. Scope object now extends `RefinedTypeOps[Scope, String]`.
To parse `Scope` use `Scope.of` or other functions provided by `RefinedTypeOps` - `from`, `unsafeFrom` or `unapply`.
Due to Scala 3 support `Scope.refine` Refined macro has been removed. Scope object now extends `RefinedTypeOps[Scope, String]`.
To parse `Scope` use `Scope.of` or other functions provided by `RefinedTypeOps` - `from`, `unsafeFrom` or `unapply`.

Since this version, scope is also made optional in [#199](https://github.com/polyvariant/sttp-oauth2/pull/199) to match the [spec](https://datatracker.ietf.org/doc/html/rfc6749#section-3.3).

## [v0.12.0](https://github.com/polyvariant/sttp-oauth2/releases/tag/v0.12.0)

### `SttpBackend` no more passed as implicit param
### `GenericBackend` no more passed as implicit param

Applying `sttp` convention, not to pass `SttpBackend` as implicit param, all methods that require it (like constructor of `ClientCredentialsProvider`) have been changed to require this as explicit parameter.
Applying `sttp` convention, not to pass `GenericBackend` as implicit param, all methods that require it (like constructor of `ClientCredentialsProvider`) have been changed to require this as explicit parameter.

Change

```scala
implicit val backend: SttpBackend[IO, Any] = ???
implicit val backend: GenericBackend[IO, Any] = ???
ClientCredentialsProvider.instance[IO](tokenUrl, tokenIntrospectionUrl, clientId, clientSecret)
```

into:

```scala
val backend: SttpBackend[IO, Any] = ???
val backend: GenericBackend[IO, Any] = ???
ClientCredentialsProvider[IO](tokenUrl, tokenIntrospectionUrl, clientId, clientSecret)(backend)
```

### Split `ClientCredentialsProvider`

`ClientCredentialsProvider` has been split into `AccessTokenProvider` and `TokenIntrospection`. This allows using better scoped traits without a need to provide redundant token introspection url if there is only need for requesting access tokens.
`ClientCredentialsProvider` has been split into `AccessTokenProvider` and `TokenIntrospection`. This allows using better scoped traits without a need to provide redundant token introspection url if there is only need for requesting access tokens.

`ClientCredentialsProvider` has been left as a sum of both traits for smoother migration, so in most cases no changes would be required during the migration.

### Caching

In this release modules `oauth2-cache-xx` have been introduced, that contain cache based `AccessTokenProvider` for `cats-effect2` and `Future`. This has lead to removal of `SttpOauth2ClientCredentialsCatsBackend` and `SttpOauth2ClientCredentialsFutureBackend`. Instead a generic `SttpOauth2ClientCredentialsBackend` should be used with a `AccessTokenProvider` of your choice.
In this release modules `oauth2-cache-xx` have been introduced, that contain cache based `AccessTokenProvider` for `cats-effect2` and `Future`. This has lead to removal of `SttpOauth2ClientCredentialsCatsBackend` and `SttpOauth2ClientCredentialsFutureBackend`. Instead a generic `SttpOauth2ClientCredentialsBackend` should be used with a `AccessTokenProvider` of your choice.

To build cached `SttpBackend`:
To build cached `GenericBackend`:
- replace dependency of `sttp-oauth2-backend-xx` with `sttp-oauth2-cache-xx`
- replace creation of `SttpOauth2ClientCredentialsXXXBackend` with the following example adjusted to your needs:

```scala
val accessTokenProvider = AccessTokenProvider[IO](tokenUrl, clientId, clientSecret)(backend)
CachingAccessTokenProvider.refCacheInstance[IO](accessTokenProvider).map { cachingAccessTokenProvider =>
CachingAccessTokenProvider.refCacheInstance[IO](accessTokenProvider).map { cachingAccessTokenProvider =>
SttpOauth2ClientCredentialsBackend[IO, Any](cachingAccessTokenProvider)(scope)
}
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import org.polyvariant.sttp.oauth2.common._
import org.polyvariant.sttp.oauth2.common.Error.OAuth2Error
import org.polyvariant.sttp.oauth2.json.JsonDecoder
import eu.timepit.refined.types.string.NonEmptyString
import sttp.client3.SttpBackend
import sttp.client4.GenericBackend
import sttp.model.Uri
import sttp.monad.MonadError
import sttp.monad.syntax._
Expand All @@ -30,13 +30,13 @@ object AccessTokenProvider {
clientId: NonEmptyString,
clientSecret: Secret[String]
)(
backend: SttpBackend[F, Any]
backend: GenericBackend[F, Any]
)(
implicit decoder: JsonDecoder[ClientCredentialsToken.AccessTokenResponse],
oAuth2ErrorDecoder: JsonDecoder[OAuth2Error]
): AccessTokenProvider[F] =
new AccessTokenProvider[F] {
implicit val F: MonadError[F] = backend.responseMonad
implicit val F: MonadError[F] = backend.monad

override def requestToken(scope: Option[Scope]): F[ClientCredentialsToken.AccessTokenResponse] =
ClientCredentials
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import cats.implicits._
import org.polyvariant.sttp.oauth2.common._
import org.polyvariant.sttp.oauth2.AuthorizationCodeProvider.Config
import org.polyvariant.sttp.oauth2.json.JsonDecoder
import sttp.client3._
import sttp.client4._
import sttp.model.HeaderNames
import sttp.model.Uri
import sttp.monad.MonadError
Expand Down Expand Up @@ -41,9 +41,9 @@ object AuthorizationCode {
clientId: String,
clientSecret: Secret[String]
)(
backend: SttpBackend[F, Any]
backend: GenericBackend[F, Any]
): F[RT] = {
implicit val F: MonadError[F] = backend.responseMonad
implicit val F: MonadError[F] = backend.monad
backend
.send {
basicRequest
Expand Down Expand Up @@ -72,9 +72,9 @@ object AuthorizationCode {
clientSecret: Secret[String],
scopeOverride: ScopeSelection
)(
backend: SttpBackend[F, Any]
backend: GenericBackend[F, Any]
): F[RT] = {
implicit val F: MonadError[F] = backend.responseMonad
implicit val F: MonadError[F] = backend.monad
backend
.send {
basicRequest
Expand Down Expand Up @@ -111,7 +111,7 @@ object AuthorizationCode {
clientSecret: Secret[String],
authCode: String
)(
backend: SttpBackend[F, Any]
backend: GenericBackend[F, Any]
): F[RT] =
convertAuthCodeToUser[F, Uri, RT](tokenUri, authCode, redirectUri.toString, clientId, clientSecret)(backend)

Expand All @@ -131,7 +131,7 @@ object AuthorizationCode {
refreshToken: String,
scopeOverride: ScopeSelection = ScopeSelection.KeepExisting
)(
backend: SttpBackend[F, Any]
backend: GenericBackend[F, Any]
): F[RT] =
performTokenRefresh[F, Uri, RT](tokenUri, refreshToken, clientId, clientSecret, scopeOverride)(backend)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import org.polyvariant.sttp.oauth2.json.JsonDecoder
import eu.timepit.refined.api.Refined
import eu.timepit.refined.refineV
import eu.timepit.refined.string.Url
import sttp.client3._
import sttp.client4._
import sttp.model.Uri

/** Provides set of functions to simplify oauth2 identity provider integration. Use the `instance` companion object method to create
Expand Down Expand Up @@ -125,7 +125,7 @@ object AuthorizationCodeProvider {
clientSecret: Secret[String],
pathsConfig: Config = Config.default
)(
backend: SttpBackend[F, Any]
backend: GenericBackend[F, Any]
): AuthorizationCodeProvider[Refined[String, Url], F] =
new AuthorizationCodeProvider[Refined[String, Url], F] {

Expand Down Expand Up @@ -167,7 +167,7 @@ object AuthorizationCodeProvider {
clientSecret: Secret[String],
pathsConfig: Config = Config.default
)(
backend: SttpBackend[F, Any]
backend: GenericBackend[F, Any]
): AuthorizationCodeProvider[Uri, F] =
new AuthorizationCodeProvider[Uri, F] {
private val tokenUri = baseUrl.addPath(pathsConfig.tokenPath.values)
Expand Down
Loading