chore: upgrade to v3 guide
first version with sed scripts.
This commit is contained in:
parent
434b2e62d8
commit
49f252f37e
1 changed files with 340 additions and 0 deletions
340
UPGRADING.md
Normal file
340
UPGRADING.md
Normal file
|
@ -0,0 +1,340 @@
|
||||||
|
# Upgrading
|
||||||
|
|
||||||
|
All commands are executed from the root of the project that imports oidc packages.
|
||||||
|
`sed` commands are created with GNU `sed` in mind and might need alternate syntax
|
||||||
|
on non-GNU systems, such as MacOS or the GNU sed command to be installed manually.
|
||||||
|
|
||||||
|
## V2 to V3
|
||||||
|
|
||||||
|
As first steps we will:
|
||||||
|
1. Download the latest v3 module;
|
||||||
|
2. Replace imports in all Go files;
|
||||||
|
3. Tidy the module file;
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get -u github.com/zitadel/oidc/v3
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/github\.com\/zitadel\/oidc\/v2/github.com\/zitadel\/oidc\/v3/g'
|
||||||
|
go mod tidy
|
||||||
|
```
|
||||||
|
|
||||||
|
### global
|
||||||
|
|
||||||
|
#### go-jose package
|
||||||
|
|
||||||
|
`gopkg.in/square/go-jose.v2` import has been changed to `github.com/go-jose/go-jose/v3`.
|
||||||
|
That means that the imported types are also changed and imports need to be adapted.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/gopkg.in\/square\/go-jose\.v2/github.com\/go-jose\/go-jose\/v3/g'
|
||||||
|
go mod tidy
|
||||||
|
```
|
||||||
|
|
||||||
|
### op
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/zitadel/oidc/v3/pkg/op"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Logger
|
||||||
|
|
||||||
|
RequestError...
|
||||||
|
AuthRequestError...
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
#### AccessTokenVerifier
|
||||||
|
|
||||||
|
`AccessTokenVerifier` interface has become a struct type. `NewAccessTokenVerifier` now returns a pointer to `AccessTokenVerifier`.
|
||||||
|
Variable and struct fields declarations need to be changed from `op.AccessTokenVerifier` to `*op.AccessTokenVerifier`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/\bop\.AccessTokenVerifier\b/*op.AccessTokenVerifier/g'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### JWTProfileVerifier
|
||||||
|
|
||||||
|
`JWTProfileVerifier` interface has become a struct type. `NewJWTProfileVerifier` now returns a pointer to `JWTProfileVerifier`.
|
||||||
|
Variable and struct fields declarations need to be changed from `op.JWTProfileVerifier` to `*op.JWTProfileVerifier`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/\bop\.JWTProfileVerifier\b/*op.JWTProfileVerifier/g'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### IDTokenHintVerifier
|
||||||
|
|
||||||
|
`IDTokenHintVerifier` interface has become a struct type. `NewIDTokenHintVerifier` now returns a pointer to `IDTokenHintVerifier`.
|
||||||
|
Variable and struct fields declarations need to be changed from `op.IDTokenHintVerifier` to `*op.IDTokenHintVerifier`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/\bop\.IDTokenHintVerifier\b/*op.IDTokenHintVerifier/g'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### ParseRequestObject
|
||||||
|
|
||||||
|
`ParseRequestObject` no longer returns `*oidc.AuthRequest` as it already operates on the pointer for the passed `authReq` argument. As such the argument and the return value were the same pointer. Callers can just use the original `*oidc.AuthRequest` now.
|
||||||
|
|
||||||
|
#### Endpoint Configuration
|
||||||
|
|
||||||
|
`Endpoint`s returned from `Configuration` interface methods are now pointers. Usually, `op.Provider` is the main implementation of the `Configuration` interface. However, if a custom implementation is used, you should be able to update it using the following:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/AuthorizationEndpoint() Endpoint/AuthorizationEndpoint() *Endpoint/g' \
|
||||||
|
-e 's/TokenEndpoint() Endpoint/TokenEndpoint() *Endpoint/g' \
|
||||||
|
-e 's/IntrospectionEndpoint() Endpoint/IntrospectionEndpoint() *Endpoint/g' \
|
||||||
|
-e 's/UserinfoEndpoint() Endpoint/UserinfoEndpoint() *Endpoint/g' \
|
||||||
|
-e 's/RevocationEndpoint() Endpoint/RevocationEndpoint() *Endpoint/g' \
|
||||||
|
-e 's/EndSessionEndpoint() Endpoint/EndSessionEndpoint() *Endpoint/g' \
|
||||||
|
-e 's/KeysEndpoint() Endpoint/KeysEndpoint() *Endpoint/g' \
|
||||||
|
-e 's/DeviceAuthorizationEndpoint() Endpoint/DeviceAuthorizationEndpoint() *Endpoint/g'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CreateDiscoveryConfig
|
||||||
|
|
||||||
|
`CreateDiscoveryConfig` now takes a context as first argument. The following adds `context.TODO()` to the function:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/op\.CreateDiscoveryConfig(/op.CreateDiscoveryConfig(context.TODO(), /g'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### CreateRouter
|
||||||
|
|
||||||
|
`CreateRouter` now returns a `chi.Router` instead of `*mux.Router`.
|
||||||
|
Usually this function is called when the Provider is constructed and not by package consumers.
|
||||||
|
However if your project does call this function directly, manual update of the code is required.
|
||||||
|
|
||||||
|
#### DeviceAuthorizationStorage
|
||||||
|
|
||||||
|
`DeviceAuthorizationStorage` dropped the following methods:
|
||||||
|
|
||||||
|
- `GetDeviceAuthorizationByUserCode`
|
||||||
|
- `CompleteDeviceAuthorization`
|
||||||
|
- `DenyDeviceAuthorization`
|
||||||
|
|
||||||
|
These methods proved not to be required from a library point of view.
|
||||||
|
Implementations of a device authorization flow may take care of these calls in a way they see fit.
|
||||||
|
|
||||||
|
#### AuthorizeCodeChallenge
|
||||||
|
|
||||||
|
The `AuthorizeCodeChallenge` function now only takes the `CodeVerifier` argument, instead of the complete `*oidc.AccessTokenRequest`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/op\.AuthorizeCodeChallenge(tokenReq/op.AuthorizeCodeChallenge(tokenReq.CodeVerifier/g'
|
||||||
|
```
|
||||||
|
|
||||||
|
### client
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/zitadel/oidc/v3/pkg/client"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Context
|
||||||
|
|
||||||
|
All client calls now take a context as first argument. The following adds `context.TODO()` to all the affected functions:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/client\.Discover(/client.Discover(context.TODO(), /g' \
|
||||||
|
-e 's/client\.CallTokenEndpoint(/client.CallTokenEndpoint(context.TODO(), /g' \
|
||||||
|
-e 's/client\.CallEndSessionEndpoint(/client.CallEndSessionEndpoint(context.TODO(), /g' \
|
||||||
|
-e 's/client\.CallRevokeEndpoint(/client.CallRevokeEndpoint(context.TODO(), /g' \
|
||||||
|
-e 's/client\.CallTokenExchangeEndpoint(/client.CallTokenExchangeEndpoint(context.TODO(), /g' \
|
||||||
|
-e 's/client\.CallDeviceAuthorizationEndpoint(/client.CallDeviceAuthorizationEndpoint(context.TODO(), /g' \
|
||||||
|
-e 's/client\.JWTProfileExchange(/client.JWTProfileExchange(context.TODO(), /g'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### keyFile type
|
||||||
|
|
||||||
|
The `keyFile` struct type is now exported a `KeyFile` and returned by the `ConfigFromKeyFile` and `ConfigFromKeyFileData`. No changes are needed on the caller's side.
|
||||||
|
|
||||||
|
### client/profile
|
||||||
|
|
||||||
|
The package now defines a new interface `TokenSource` which compliments the `oauth2.TokenSource` with a `TokenCtx` method, so that a context can be explicitly added on each call. Users can migrate to the new method when they whish.
|
||||||
|
|
||||||
|
`NewJWTProfileTokenSource` now takes a context as first argument, so do the related `NewJWTProfileTokenSourceFromKeyFile` and `NewJWTProfileTokenSourceFromKeyFileData`. The context is used for the Discovery request.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/profile\.NewJWTProfileTokenSource(/profile.NewJWTProfileTokenSource(context.TODO(), /g' \
|
||||||
|
-e 's/profile\.NewJWTProfileTokenSourceFromKeyFileData(/profile.NewJWTProfileTokenSourceFromKeyFileData(context.TODO(), /g' \
|
||||||
|
-e 's/profile\.NewJWTProfileTokenSourceFromKeyFile(/profile.NewJWTProfileTokenSourceFromKeyFile(context.TODO(), /g'
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### client/rp
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/zitadel/oidc/v3/pkg/client/rs"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Discover
|
||||||
|
|
||||||
|
The `Discover` function has been removed. Use `client.Discover` instead.
|
||||||
|
|
||||||
|
#### Context
|
||||||
|
|
||||||
|
Most `rp` functions now require a context as first argument. The following adds `context.TODO()` to the function that have no additional changes. Functions with more complex changes are documented below.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/rp\.NewRelyingPartyOIDC(/rp.NewRelyingPartyOIDC(context.TODO(), /g' \
|
||||||
|
-e 's/rp\.EndSession(/rp.EndSession(context.TODO(), /g' \
|
||||||
|
-e 's/rp\.RevokeToken(/rp.RevokeToken(context.TODO(), /g' \
|
||||||
|
-e 's/rp\.DeviceAuthorization(/rp.DeviceAuthorization(context.TODO(), /g'
|
||||||
|
```
|
||||||
|
|
||||||
|
Remember to replace `context.TODO()` with a context that is applicable for your app, where possible.
|
||||||
|
|
||||||
|
#### RefreshAccessToken
|
||||||
|
|
||||||
|
1. Renamed to `RefreshTokens`;
|
||||||
|
2. A context must be passed;
|
||||||
|
3. An `*oidc.Tokens` object is now returned, which included an ID Token if it was returned by the server;
|
||||||
|
4. The function is now generic and requires a type argument for the `IDTokenClaims` implementation inside the returned `oidc.Tokens` object;
|
||||||
|
|
||||||
|
For most use cases `*oidc.IDTokenClaims` can be used as type argument. A custom implementation of `oidc.IDClaims` can be used if type-safe access to custom claims is required.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/rp\.RefreshAccessToken(/rp.RefreshTokens[*oidc.IDTokenClaims](context.TODO(), /g'
|
||||||
|
```
|
||||||
|
|
||||||
|
Users that called `tokens.Extra("id_token").(string)` and a subsequent `VerifyTokens` to get the claims, no longer need to do this. The ID token is verified (when present) by `RefreshTokens` already.
|
||||||
|
|
||||||
|
|
||||||
|
#### Userinfo
|
||||||
|
|
||||||
|
1. A context must be passed as first argument;
|
||||||
|
2. The function is now generic and requires a type argument for the returned user info object;
|
||||||
|
|
||||||
|
For most use cases `*oidc.UserInfo` can be used a type argument. A [custom implementation](https://pkg.go.dev/github.com/zitadel/oidc/v3/pkg/client/rp#example-Userinfo-Custom) of `rp.SubjectGetter` can be used if type-safe access to custom claims is required.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/rp\.Userinfo(/rp.Userinfo[*oidc.UserInfo](context.TODO(), /g'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### UserinfoCallback
|
||||||
|
|
||||||
|
`UserinfoCallback` has an additional type argument fot the `UserInfo` object. Typically the type argument can be inferred by the compiler, by the function that is passed. The actual code update cannot be done by a simple `sed` script and depends on how the caller implemented the function.
|
||||||
|
|
||||||
|
|
||||||
|
#### IDTokenVerifier
|
||||||
|
|
||||||
|
`IDTokenVerifier` interface has become a struct type. `NewIDTokenVerifier` now returns a pointer to `IDTokenVerifier`.
|
||||||
|
Variable and struct fields declarations need to be changed from `rp.IDTokenVerifier` to `*rp.AccessTokenVerifier`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/\brp\.IDTokenVerifier\b/*rp.IDTokenVerifier/g'
|
||||||
|
```
|
||||||
|
|
||||||
|
### client/rs
|
||||||
|
|
||||||
|
```go
|
||||||
|
import "github.com/zitadel/oidc/v3/pkg/client/rs"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### NewResourceServer
|
||||||
|
|
||||||
|
The `NewResourceServerClientCredentials` and `NewResourceServerJWTProfile` constructor functions now take a context as first argument.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/rs\.NewResourceServerClientCredentials(/rs.NewResourceServerClientCredentials(context.TODO(), /g' \
|
||||||
|
-e 's/rs\.NewResourceServerJWTProfile(/rs.NewResourceServerJWTProfile(context.TODO(), /g'
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Introspect
|
||||||
|
|
||||||
|
`Introspect` is now generic and requires a type argument for the returned introspection response. For most use cases `*oidc.IntrospectionResponse` can be used as type argument. Any other response type if type-safe access to [custom claims](https://pkg.go.dev/github.com/zitadel/oidc/v3/pkg/client/rs#example-Introspect-Custom) is required.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/rs\.Introspect(/rs.Introspect[*oidc.IntrospectionResponse](/g'
|
||||||
|
```
|
||||||
|
|
||||||
|
### client/tokenexchange
|
||||||
|
|
||||||
|
The `TokenExchanger` constructor functions `NewTokenExchanger` and `NewTokenExchangerClientCredentials` now take a context as first argument.
|
||||||
|
As well as the `ExchangeToken` function.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/tokenexchange\.NewTokenExchanger(/tokenexchange.NewTokenExchanger(context.TODO(), /g' \
|
||||||
|
-e 's/tokenexchange\.NewTokenExchangerClientCredentials(/tokenexchange.NewTokenExchangerClientCredentials(context.TODO(), /g' \
|
||||||
|
-e 's/tokenexchange\.ExchangeToken(/tokenexchange.ExchangeToken(context.TODO(), /g'
|
||||||
|
```
|
||||||
|
|
||||||
|
### oidc
|
||||||
|
|
||||||
|
#### SpaceDelimitedArray
|
||||||
|
|
||||||
|
The `SpaceDelimitedArray` type's `Encode()` function has been renamed to `String()` so it implements the `fmt.Stringer` interface. If the `Encode` method was called by a package consumer, it should be changed manually.
|
||||||
|
|
||||||
|
#### Verifier
|
||||||
|
|
||||||
|
The `Verifier` interface as been changed into a struct type. The struct type is aliased in the `op` and `rp` packages for the specific token use cases. See the relevant section above.
|
||||||
|
|
||||||
|
### Full script
|
||||||
|
|
||||||
|
For the courageous this is the full `sed` script which combines all the steps described above.
|
||||||
|
It should migrate most of the code in a repository to a more-or-less compilable state,
|
||||||
|
using defaults such as `context.TODO()` where possible.
|
||||||
|
|
||||||
|
Warnings:
|
||||||
|
- Again, this is written for **GNU sed** not the posix variant.
|
||||||
|
- Assumes imports that use the package names, not aliases.
|
||||||
|
- Do this on a project with version control (eg Git), that allows you to rollback if things went wrong.
|
||||||
|
- The script has been tested on the [ZITADEL](https://github.com/zitadel/zitadel) project, but we do not use all affected symbols. Parts of the script are mere guesswork.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go get -u github.com/zitadel/oidc/v3
|
||||||
|
find . -type f -name '*.go' | xargs sed -i \
|
||||||
|
-e 's/github\.com\/zitadel\/oidc\/v2/github.com\/zitadel\/oidc\/v3/g' \
|
||||||
|
-e 's/gopkg.in\/square\/go-jose\.v2/github.com\/go-jose\/go-jose\/v3/g' \
|
||||||
|
-e 's/\bop\.AccessTokenVerifier\b/*op.AccessTokenVerifier/g' \
|
||||||
|
-e 's/\bop\.JWTProfileVerifier\b/*op.JWTProfileVerifier/g' \
|
||||||
|
-e 's/\bop\.IDTokenHintVerifier\b/*op.IDTokenHintVerifier/g' \
|
||||||
|
-e 's/AuthorizationEndpoint() Endpoint/AuthorizationEndpoint() *Endpoint/g' \
|
||||||
|
-e 's/TokenEndpoint() Endpoint/TokenEndpoint() *Endpoint/g' \
|
||||||
|
-e 's/IntrospectionEndpoint() Endpoint/IntrospectionEndpoint() *Endpoint/g' \
|
||||||
|
-e 's/UserinfoEndpoint() Endpoint/UserinfoEndpoint() *Endpoint/g' \
|
||||||
|
-e 's/RevocationEndpoint() Endpoint/RevocationEndpoint() *Endpoint/g' \
|
||||||
|
-e 's/EndSessionEndpoint() Endpoint/EndSessionEndpoint() *Endpoint/g' \
|
||||||
|
-e 's/KeysEndpoint() Endpoint/KeysEndpoint() *Endpoint/g' \
|
||||||
|
-e 's/DeviceAuthorizationEndpoint() Endpoint/DeviceAuthorizationEndpoint() *Endpoint/g' \
|
||||||
|
-e 's/op\.CreateDiscoveryConfig(/op.CreateDiscoveryConfig(context.TODO(), /g' \
|
||||||
|
-e 's/op\.AuthorizeCodeChallenge(tokenReq/op.AuthorizeCodeChallenge(tokenReq.CodeVerifier/g' \
|
||||||
|
-e 's/client\.Discover(/client.Discover(context.TODO(), /g' \
|
||||||
|
-e 's/client\.CallTokenEndpoint(/client.CallTokenEndpoint(context.TODO(), /g' \
|
||||||
|
-e 's/client\.CallEndSessionEndpoint(/client.CallEndSessionEndpoint(context.TODO(), /g' \
|
||||||
|
-e 's/client\.CallRevokeEndpoint(/client.CallRevokeEndpoint(context.TODO(), /g' \
|
||||||
|
-e 's/client\.CallTokenExchangeEndpoint(/client.CallTokenExchangeEndpoint(context.TODO(), /g' \
|
||||||
|
-e 's/client\.CallDeviceAuthorizationEndpoint(/client.CallDeviceAuthorizationEndpoint(context.TODO(), /g' \
|
||||||
|
-e 's/client\.JWTProfileExchange(/client.JWTProfileExchange(context.TODO(), /g' \
|
||||||
|
-e 's/profile\.NewJWTProfileTokenSource(/profile.NewJWTProfileTokenSource(context.TODO(), /g' \
|
||||||
|
-e 's/profile\.NewJWTProfileTokenSourceFromKeyFileData(/profile.NewJWTProfileTokenSourceFromKeyFileData(context.TODO(), /g' \
|
||||||
|
-e 's/profile\.NewJWTProfileTokenSourceFromKeyFile(/profile.NewJWTProfileTokenSourceFromKeyFile(context.TODO(), /g' \
|
||||||
|
-e 's/rp\.NewRelyingPartyOIDC(/rp.NewRelyingPartyOIDC(context.TODO(), /g' \
|
||||||
|
-e 's/rp\.EndSession(/rp.EndSession(context.TODO(), /g' \
|
||||||
|
-e 's/rp\.RevokeToken(/rp.RevokeToken(context.TODO(), /g' \
|
||||||
|
-e 's/rp\.DeviceAuthorization(/rp.DeviceAuthorization(context.TODO(), /g' \
|
||||||
|
-e 's/rp\.RefreshAccessToken(/rp.RefreshTokens[*oidc.IDTokenClaims](context.TODO(), /g' \
|
||||||
|
-e 's/rp\.Userinfo(/rp.Userinfo[*oidc.UserInfo](context.TODO(), /g' \
|
||||||
|
-e 's/\brp\.IDTokenVerifier\b/*rp.IDTokenVerifier/g' \
|
||||||
|
-e 's/rs\.NewResourceServerClientCredentials(/rs.NewResourceServerClientCredentials(context.TODO(), /g' \
|
||||||
|
-e 's/rs\.NewResourceServerJWTProfile(/rs.NewResourceServerJWTProfile(context.TODO(), /g' \
|
||||||
|
-e 's/rs\.Introspect(/rs.Introspect[*oidc.IntrospectionResponse](/g' \
|
||||||
|
-e 's/tokenexchange\.NewTokenExchanger(/tokenexchange.NewTokenExchanger(context.TODO(), /g' \
|
||||||
|
-e 's/tokenexchange\.NewTokenExchangerClientCredentials(/tokenexchange.NewTokenExchangerClientCredentials(context.TODO(), /g' \
|
||||||
|
-e 's/tokenexchange\.ExchangeToken(/tokenexchange.ExchangeToken(context.TODO(), /g'
|
||||||
|
go mod tidy
|
||||||
|
```
|
Loading…
Add table
Add a link
Reference in a new issue