Skip to content

Commit

Permalink
Feature refresh token (#9)
Browse files Browse the repository at this point in the history
AuthService.RefreshAuthToken() implemented


* GitHub Workflows
  - enabling workflows on feature and issue branches
  - stepping go version to 1.18

* basic evaluation added to `TestTokenRefreshRoutine`
* CHANGELOG file added to the repo
* verbose mode added to `Client`
  • Loading branch information
theriverman authored Aug 3, 2022
1 parent b2c6c68 commit 0eed88c
Show file tree
Hide file tree
Showing 14 changed files with 383 additions and 65 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Go

on:
push:
branches: [ 'master', 'ci-docker-test' ]
branches: [ 'master', 'ci-docker-test', 'feature_*', 'issue_*' ]
pull_request:
branches: [ 'master', 'ci-docker-test' ]

Expand All @@ -16,7 +16,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v2
with:
go-version: 1.15
go-version: 1.18

- name: Build
run: go build -v ./
Expand Down
3 changes: 3 additions & 0 deletions .vscode/settings.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"go.testFlags": ["-v"]
}
95 changes: 95 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Change Log
All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).

## [1.5.0] - 2022-08-03

Taiga has changed its authentication system to a more sophisticated JWT implementation. This requires the user to refresh their token every 24 hours (default setting). If you're using Taigo in a system which tends to run for longer than 24 hours, such as, a webserver where your `taigo.Client` instance is preserved for days/weeks/months, then you need a way to keep your stored token fresh.

Taigo gets this task done automatically by polling a ticker in a goroutine and refreshing the stored tokens every 12 hours.

If you'd like to implement your own token refreshing mechanism, you have two options:
- implement your own routine based on `defaultTokenRefreshRoutine(c *Client, ticker *time.Ticker)`
- disable the `RefreshTokenRoutine` by calling `DisableAutomaticTokenRefresh()` and do the Token update your way (don't forget to update the contents of `Client.Headers`).

### Added
- `AuthService.RefreshAuthToken()` implemented
- New fields added to `Client`:
- `AutoRefreshDisabled`
- `AutoRefreshTickerDuration`
- `TokenRefreshTicker`
- New methods added to `Client`:
- `DisableAutomaticTokenRefresh()`

### Changed

- MAJOR Changed the signature of `*Client.AuthByToken(tokenType, token, refreshToken string) error`.
It now requires `refreshToken` too.
- GitHub Workflows: Stepped go version to 1.18
- GitHub Workflows: Tests enabled on `feature_*` and `issue_*` branches

### Fixed

- [TAIGO-8](https://github.com/theriverman/taigo/issues/8)
MAJOR Add missing Auth/Refresh auth token

## [1.4.0] - 2021-02-28

### Added

- Support for getting, creating and editing Taiga Issue objects
- Added custom attribute get/update example for user stories
- Added support for working easily in a specific project's scope via *ProjectService

### Changed

- TgObjectCustomAttributeValues are now exported and can be extended on-the-fly

### Fixed

- Struct members representing various agile points have been changed from regular int to float64

## [1.3.0] - 2020-10-04

### Added

- Support for custom attribute handling
- Support for working easily in a specific project's scope via `*ProjectService`

### Changed

### Fixed

## [1.2.2] - 2020-10-04

### Added

- A simplified init was implemented

### Changed

- update `contribute/main.go`

### Fixed

## [1.1.0] - 2020-09-23

### Added

### Changed

- Models have been improved for better accuracy

### Fixed

## [1.0.0] - 2020-09-18

### Added

- First version of the product

### Changed

### Fixed
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ Taiga is an Agile, Free and Open Source Project Management Tool.

Should you have any ideas or recommendations, feel free to report it as an issue or open a pull request.

For the most recent changes, see [CHANGELOG](./CHANGELOG.md).

## Known Limitations
* Some model members holding integers (i.e. `backlog_order`) were implemented using `int` instead of `int64` or rather `uint64` in some cases which results in runtime errors on machines with **32-bit arm** CPUs.

Expand Down Expand Up @@ -308,6 +310,17 @@ if err != nil {
}
```

# Logging & Verbose Mode
## Logging

## Verbose Mode
Verbose mode can be enabled by setting the `Verbose` field to `true` in `taiga.Client`. For example:
```go
client := taiga.Client{
Verbose: true
}
```

# Contribution
You're contribution would be much appreciated! <br>
Feel free to open Issue tickets or create Pull requests. <br>
Expand All @@ -319,6 +332,7 @@ For more details, see [TAIGO Contribution](CONTRIBUTION.md).
## Branching Strategy
* **master** is <i>always</i> stable
* **develop** is *not* <i>always</i> stable
* **feature_\*** branches are used for introducing larger changes

# Licenses & Recognitions
| Product | License | Author |
Expand Down
25 changes: 22 additions & 3 deletions auth.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package taigo

import "log"

// AuthService is a handle to actions related to Auths
//
// https://taigaio.github.io/taiga-doc/dist/api.html#auths
Expand All @@ -11,6 +9,27 @@ type AuthService struct {
Endpoint string
}

// RefreshAuthToken => https://docs.taiga.io/api.html#auth-refresh
//
// Generates a new pair of bearer and refresh token
// If `selfUpdate` is true, `*Client` is refreshed with the returned token values
func (s *AuthService) RefreshAuthToken(selfUpdate bool) (RefreshResponse *RefreshToken, err error) {
url := s.client.MakeURL(s.Endpoint, "refresh")
data := RefreshToken{
AuthToken: s.client.Token,
Refresh: s.client.RefreshToken,
}
_, err = s.client.Request.Post(url, &data, &RefreshResponse)
if err != nil {
return nil, err
}
if selfUpdate {
s.client.Token = RefreshResponse.AuthToken
s.client.RefreshToken = RefreshResponse.Refresh
}
return
}

// PublicRegistry => https://taigaio.github.io/taiga-doc/dist/api.html#auth-public-registry
/*
type with value "public"
Expand Down Expand Up @@ -45,10 +64,10 @@ func (s *AuthService) login(credentials *Credentials) (*UserAuthenticationDetail

_, err := s.client.Request.Post(url, &credentials, &u)
if err != nil {
log.Println("Failed to authenticate to Taiga.")
return nil, err
}
s.client.Token = u.AuthToken
s.client.RefreshToken = u.Refresh
s.client.setToken()
return &u, nil
}
24 changes: 24 additions & 0 deletions auth.models.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,27 @@ type Credentials struct {
Token string `json:"token,omitempty"`
AcceptedTerms bool `json:"accepted_terms,omitempty"` // Required for registration only
}

// UserAuthenticationDetail is a superset of User extended by an AuthToken field
type UserAuthenticationDetail struct {
AuthToken string `json:"auth_token"`
Refresh string `json:"refresh"`
User // Embedding type User struct
}

// AsUser returns a *User from *UserAuthenticationDetail
// The AuthToken can be accessed from `User` via `.GetToken()`
func (u *UserAuthenticationDetail) AsUser() *User {
user := &User{}
err := convertStructViaJSON(u, user)
if err != nil {
return nil
}
user.authToken = u.AuthToken
return user
}

type RefreshToken struct {
AuthToken string `json:"auth_token,omitempty"`
Refresh string `json:"refresh,omitempty"`
}
Loading

0 comments on commit 0eed88c

Please sign in to comment.