Add support to login using identity from an identity-aware proxy #715

Open
branchmispredictor wants to merge 9 commits from branchmispredictor/api:feature/identity-aware-proxy into main

Description

This PR adds the api component to allow users to sign in using an identity provided by an Identity-Aware Proxy (IAP). One such example is Pomerium.

The IAP (in this case Pomerium) passes a signed JWT in an HTTP header to any backend service running behind it. This JWT contains a claim for email, iss, sub, and other typical items. To validate the JWT, we get a public key from the proxy's jwks url.

This PR has grown a good bit. There is an identityawareproxy middleware on all authenticated endpoints and on a special IAP token endpoint. It validates the identity from the proxy and attaches it to the echo context. All internal auth will use this identity if it exists.

The identityawareproxy token endpoint, and the passing of tokens to the frontend of a new auth type is to:

  1. Ensure the frontend has a userID, username, etc and to not drastically overhall the frontend
  2. To not require changing the existing frontend -> backend JWT validation checks to somehow make them optional in certain configurations

The token endpoint can be called at any time to get a new token based on the IAP identity.

TODO: modify the frontend to call the endpoint often enough

Other Changes

This PR moved the claims map into a struct. This removes the potential for miscopying or mistyping a string key when accessing a claim from the claims map. This also removes a potential issue where claim values could be truncated (e.g. in int64(claims["sharedByID"].(float64)), if the sharedById was above the maximum integer a float64 could hold, that value would be truncated).

Claims were also disambiguated to prevent type confusion. Now there is no chance that a linkshare JWT can me mistaken for a user JWT (previously both simply used an "id" claim, now they are "user_id" vs "link_share_id"). Not every caller was checking the JWT "type" claim to see if the token was for a user or a link share to begin with, and this removes the need to do so altogether.

Checklist

  • [✓] I added or improved tests
  • [✓] I added or improved docs for my feature
    • [✓] Swagger (including mage do-the-swag)
    • [✓] Error codes
    • [✓] New config options (including adding them to config.yml.saml and running mage generate-docs)
# Description This PR adds the api component to allow users to sign in using an identity provided by an Identity-Aware Proxy (IAP). One such example is [Pomerium](https://www.pomerium.io/docs/topics/getting-users-identity.html). The IAP (in this case Pomerium) passes a signed JWT in an HTTP header to any backend service running behind it. This JWT contains a claim for `email`, `iss`, `sub`, and other typical items. To validate the JWT, we get a public key from the proxy's jwks url. This PR has grown a good bit. There is an identityawareproxy middleware on all authenticated endpoints and on a special IAP token endpoint. It validates the identity from the proxy and attaches it to the echo context. All internal auth will use this identity if it exists. The identityawareproxy token endpoint, and the passing of tokens to the frontend of a new auth type is to: 1. Ensure the frontend has a userID, username, etc and to not drastically overhall the frontend 2. To not require changing the existing frontend -> backend JWT validation checks to somehow make them optional in certain configurations The token endpoint can be called at any time to get a new token based on the IAP identity. TODO: modify the frontend to call the endpoint often enough ## Other Changes This PR moved the claims map into a struct. This removes the potential for miscopying or mistyping a string key when accessing a claim from the claims map. This also removes a potential issue where claim values could be truncated (e.g. in `int64(claims["sharedByID"].(float64))`, if the sharedById was above the maximum integer a float64 could hold, that value would be truncated). Claims were also disambiguated to prevent type confusion. Now there is no chance that a linkshare JWT can me mistaken for a user JWT (previously both simply used an "id" claim, now they are "user_id" vs "link_share_id"). Not every caller was checking the JWT "type" claim to see if the token was for a user or a link share to begin with, and this removes the need to do so altogether. # Checklist * [✓] I added or improved tests * [✓] I added or improved docs for my feature * [✓] Swagger (including `mage do-the-swag`) * [✓] Error codes * [✓] New config options (including adding them to `config.yml.saml` and running `mage generate-docs`)
branchmispredictor reviewed 2 years ago
// Auth
AuthLocalEnabled.setDefault(true)
AuthOpenIDEnabled.setDefault(false)
AuthOpenIDProviders.setDefault(make([]interface{}, 0))

This was required to stop getting a 500 on the /info endpoint.

This was required to stop getting a 500 on the /info endpoint.
Owner

Huh, that sounds a lot like a bug. I'll look into that and maybe backport it - the openid integration is pretty new and still a bit rough around the edges.

Huh, that sounds a lot like a bug. I'll look into that and maybe backport it - the openid integration is pretty new and still a bit rough around the edges.
Owner

Fixed in d2d610e0f5

Fixed in https://kolaente.dev/vikunja/api/commit/d2d610e0f5f0d8618145d4d83d4fd37bc49072ba
konrad marked this conversation as resolved
branchmispredictor reviewed 2 years ago
return auth.NewUserAuthTokenResponse(u, c)
}
func getOrCreateUser(cl *claims) (u *user.User, err error) {

This is almost an exact copy from the method in openid.go. I'll try to refactor into some common helper, but I'm not too familiar with go and how to get them to work with both different claim structs. Open to suggestions here.

This is almost an exact copy from the method in `openid.go`. I'll try to refactor into some common helper, but I'm not too familiar with go and how to get them to work with both different claim structs. Open to suggestions here.
Owner

Maybe just have the parameters of the claim like Issuer, Subject, Username and so on as function parameters? Or a separate createUserOpts struct or something like that.

Maybe just have the parameters of the claim like `Issuer`, `Subject`, `Username` and so on as function parameters? Or a separate `createUserOpts` struct or something like that.
branchmispredictor marked this conversation as resolved
branchmispredictor changed title from Add support to login using identity from an identity-aware proxy to WIP: Add support to login using identity from an identity-aware proxy 2 years ago
konrad requested changes 2 years ago
// Parse the jwt from the identity-aware proxy using the correct key
tken, err := jwt.ParseWithClaims(token, &claims{}, func(unvalidatedToken *jwt.Token) (interface{}, error) {
// Only support either ECDSA or RSA signing methods
Owner

Please document this.

Please document this.
branchmispredictor marked this conversation as resolved
// Only support either ECDSA or RSA signing methods
if _, ok := unvalidatedToken.Method.(*jwt.SigningMethodECDSA); !ok {
if _, ok := unvalidatedToken.Method.(*jwt.SigningMethodRSA); !ok {
return nil, fmt.Errorf("Unexpected signing method: %v", unvalidatedToken.Header["alg"])
Owner

Please make errors like this into custom error types which you'd then return.

Please make errors like this into custom error types which you'd then return.
branchmispredictor marked this conversation as resolved
}
keys := keyset.LookupKeyID(keyID)
if len(keys) != 1 {
Owner

What if there's more than one Key? Is that even possible? In that case, should we still just use the first one or return a different error?

What if there's more than one Key? Is that even possible? In that case, should we still just use the first one or return a different error?
}
// Validates the claims in the jwt
func (c claims) Valid() error {
Owner

Please use a pointer as the parameter, like so: c *claims.

Please use a pointer as the parameter, like so: `c *claims`.
branchmispredictor marked this conversation as resolved
// Validates the claims in the jwt
func (c claims) Valid() error {
// Validate that expiresAt and issuedAt are set and valid (with up to 1 minute of skew)
Owner

Would it make sense to make that skew configurable?

Would it make sense to make that skew configurable?
Owner

As far as I understand it, IAPs handle all the authentication related stuff and then proxy all subsequent request to the actual application (in this case Vikunja). This would mean that you'd need to add a middleware to check if an IAP was configured and if that's the case validate it and make sure the user exists and so on, essentially bypassing Vikunja's authentication methods. How are you planning to authenticate users through the seperate endpoint you created?
This would also mean you won't need any frontend changes as everything would be handled through the header.

As far as I understand it, IAPs handle all the authentication related stuff and then proxy all subsequent request to the actual application (in this case Vikunja). This would mean that you'd need to add a middleware to check if an IAP was configured and if that's the case validate it and make sure the user exists and so on, essentially bypassing Vikunja's authentication methods. How are you planning to authenticate users through the seperate endpoint you created? This would also mean you won't need any frontend changes as everything would be handled through the header.

As far as I understand it, IAPs handle all the authentication related stuff and then proxy all subsequent request to the actual application (in this case Vikunja). This would mean that you'd need to add a middleware to check if an IAP was configured and if that's the case validate it and make sure the user exists and so on, essentially bypassing Vikunja's authentication methods. How are you planning to authenticate users through the seperate endpoint you created?
This would also mean you won't need any frontend changes as everything would be handled through the header.

Yes, the IAP will be proxying all requests to the application with the JWT header set.

Initially I was envisioning a login-with-IAP-identity button that essentially works as another login button. This would support enabling multiple auth solutions if need be, for instance local auth + proxy auth.

Checking this with a middleware may be a better approach, I can try that out if you think that's reasonable. In that case, I think there are a couple of standing questions:

  • Even if the IAP identity is present, should there be an automatic login or should it require a button press (to simultaneously allow for other auth methods)
  • Same question for user creation. If one doesn't exist for the IAP identity, should it be created automatically or through some "register" action
  • Depends on the answers above, but should the Logout button be removed then?
> As far as I understand it, IAPs handle all the authentication related stuff and then proxy all subsequent request to the actual application (in this case Vikunja). This would mean that you'd need to add a middleware to check if an IAP was configured and if that's the case validate it and make sure the user exists and so on, essentially bypassing Vikunja's authentication methods. How are you planning to authenticate users through the seperate endpoint you created? > This would also mean you won't need any frontend changes as everything would be handled through the header. Yes, the IAP will be proxying all requests to the application with the JWT header set. Initially I was envisioning a login-with-IAP-identity button that essentially works as another login button. This would support enabling multiple auth solutions if need be, for instance local auth + proxy auth. Checking this with a middleware may be a better approach, I can try that out if you think that's reasonable. In that case, I think there are a couple of standing questions: * Even if the IAP identity is present, should there be an automatic login or should it require a button press (to simultaneously allow for other auth methods) * Same question for user creation. If one doesn't exist for the IAP identity, should it be created automatically or through some "register" action * Depends on the answers above, but should the Logout button be removed then?
branchmispredictor force-pushed feature/identity-aware-proxy from 7c99c9b0d0 to ba3805443c 2 years ago
Owner

Checking this with a middleware may be a better approach, I can try that out if you think that's reasonable.

I think so, please try that :slight_smiling_face:

Even if the IAP identity is present, should there be an automatic login or should it require a button press (to simultaneously allow for other auth methods)

As far as I understand it, you would not get to Vikunja through the IAP if you're not logged in, so a button would be obsolete.

Same question for user creation. If one doesn't exist for the IAP identity, should it be created automatically or through some "register" action

I think you should check if a user exists for the (iss, sub) tuple and log that user in, if no user was found create one and log them in. That's essentially what getOrCreateUser does.

Depends on the answers above, but should the Logout button be removed then?

How is logout handled in general with an IAP?

> Checking this with a middleware may be a better approach, I can try that out if you think that's reasonable. I think so, please try that :slight_smiling_face: > Even if the IAP identity is present, should there be an automatic login or should it require a button press (to simultaneously allow for other auth methods) As far as I understand it, you would not get to Vikunja through the IAP if you're not logged in, so a button would be obsolete. > Same question for user creation. If one doesn't exist for the IAP identity, should it be created automatically or through some "register" action I think you should check if a user exists for the `(iss, sub)` tuple and log that user in, if no user was found create one and log them in. That's essentially what `getOrCreateUser` does. > Depends on the answers above, but should the Logout button be removed then? How is logout handled in general with an IAP?
branchmispredictor added 2 commits 2 years ago
branchmispredictor force-pushed feature/identity-aware-proxy from 79ca2c4e2f to ce96e2b077 2 years ago
branchmispredictor added 1 commit 2 years ago
a93736187c Docs and formatting
branchmispredictor changed title from WIP: Add support to login using identity from an identity-aware proxy to Add support to login using identity from an identity-aware proxy 2 years ago
branchmispredictor added 1 commit 2 years ago
c21784df4f Fix golint errors

I've rebased the PR and hopefully fixed any remaining CI issues. Sorry for the delay, work was quite busy leading up to the holiday season. I've also updated the frontend PR to match these changes.

I've rebased the PR and hopefully fixed any remaining CI issues. Sorry for the delay, work was quite busy leading up to the holiday season. I've also updated the [frontend PR](https://kolaente.dev/vikunja/frontend/pulls/310) to match these changes.
branchmispredictor requested review from konrad 2 years ago

Hey @konrad, just wanted to check in on this PR. If it's not in an acceptable state I can work on it further. Or if it's not something you're considering accepting at this point (perhaps an auth overhaul is in the works for OAuth or something), that's fine too. I'd just like to know the general status before I start fixing merge conflicts again.

Hey @konrad, just wanted to check in on this PR. If it's not in an acceptable state I can work on it further. Or if it's not something you're considering accepting at this point (perhaps an auth overhaul is in the works for OAuth or something), that's fine too. I'd just like to know the general status before I start fixing merge conflicts again.
Owner

@branchmispredictor I'll give it another review, I just haven't found the time yet.

How is logout handled in general with an IAP?

What about logging the user out?

@branchmispredictor I'll give it another review, I just haven't found the time yet. > How is logout handled in general with an IAP? What about logging the user out?
konrad closed this pull request 2 years ago
Owner

Nothing sure why the pr was closed, that wasn't intentional.

I think that came from renaming the main branch.

Nothing sure why the pr was closed, that wasn't intentional. I think that came from renaming the main branch.
konrad reopened this pull request 2 years ago
konrad added 1 commit 2 years ago
1224b9accb
Merge branch 'main' into feature/identity-aware-proxy
konrad added 1 commit 2 years ago
81c5cb6a7a
Fix token renew after resolving conflicts
konrad requested changes 2 years ago
konrad left a comment
Owner

Thanks for refactoring! (And sorry for my very late review...)

I think this looks quite good so far, just some comments.

Just to clarify if I understood it correctly: Does using the iap middleware mean only either local auth or iap auth can be used? If that's the case, there should be a check when initializing the docs with an error if both are configured.

Thanks for refactoring! (And sorry for my very late review...) I think this looks quite good so far, just some comments. Just to clarify if I understood it correctly: Does using the iap middleware mean only either local auth or iap auth can be used? If that's the case, there should be a check when initializing the docs with an error if both are configured.
// In these cases, AuthClaims may contain hints to the user identity,
// but an outside source is the final source-of-truth for auth (e.g. Identity-Aware Proxy auth)
type AuthProvider interface {
GetWebAuth(echo.Context, *AuthClaims) (web.Auth, error)
Owner

I think this should return a *user.User since the external auth is still represented as a user in Vikunja. It's not a "new type of authentication" like link share is.

I think this should return a `*user.User` since the external auth is still represented as a user in Vikunja. It's not a "new type of authentication" like link share is.
}
// ErrorCodeIAPTokenMissing holds the unique world-error code of this error
const ErrorCodeIAPTokenMissing = 12001
Owner

This should be documented in docs/content/doc/usage/errors.md

This should be documented in `docs/content/doc/usage/errors.md`
// @Produce json
// @Success 200 {object} auth.Token
// @Failure 500 {object} models.Message "Internal error"
// @Router /auth/identityawareproxy/token [get]
Owner

Is there a special reason this is a separate endpoint instead of reusing the existing token one? It seems like this will require a frontend change?

Is there a special reason this is a separate endpoint instead of reusing the existing token one? It seems like this will require a frontend change?

There's a problem with bootstrapping auth here. The way IAPs work is by setting an http header with claims to the downstream service (vikunja-api), however javascript or front-end code does not have access to http headers.

So on initial load, there is no cookie / vikunja-jwt set so the frontend does not see us as logged in. Similarly, the existing /user/token endpoint is also unavailable because it is behind the jwt middleware and requires a jwt cookie set. So this endpoint exists outside of the jwt middleware so it can be accessed from before a user is "logged in"

There's a problem with bootstrapping auth here. The way IAPs work is by setting an http header with claims to the downstream service (vikunja-api), however javascript or front-end code does not have access to http headers. So on initial load, there is no cookie / vikunja-jwt set so the frontend does not see us as logged in. Similarly, the existing `/user/token` endpoint is also unavailable because it is behind the jwt middleware and requires a jwt cookie set. So this endpoint exists outside of the jwt middleware so it can be accessed from before a user is "logged in"
Owner

So this is the endpoint to "translate" the http header from the IAP to a Vikunja token? Wouldn't it be possible to just extend the existing middleware to look for that http header? All that'd be left then would be to extend the frontend so it somehow checks if the user is logged in (maybe by calling /api/v1/user and see if there's a 200 response coming back and then setting the frontend state to "logged in"?)

So this is the endpoint to "translate" the http header from the IAP to a Vikunja token? Wouldn't it be possible to just extend the existing middleware to look for that http header? All that'd be left then would be to extend the frontend so it somehow checks if the user is logged in (maybe by calling `/api/v1/user` and see if there's a 200 response coming back and then setting the frontend state to "logged in"?)

What I can do, is abtract this away a bit and make this an /auth/externalprovider/loggedin endpoint, so any future external auth source might also reuse the same endpoint.

Was writing that before I saw the reply. Yes, this basically translates the http header from the IAP to a vikunja token. The only problem is that the jwt middleware will error out for /api/v1/user/* if the frontend does not provide an already valid jwt as a cookie

~~What I can do, is abtract this away a bit and make this an `/auth/externalprovider/loggedin` endpoint, so any future external auth source might also reuse the same endpoint.~~ Was writing that before I saw the reply. Yes, this basically translates the http header from the IAP to a vikunja token. The only problem is that the jwt middleware will error out for /api/v1/user/* if the frontend does not provide an already valid jwt as a cookie
Owner

How would that look in the frontend, would it call that endpoint every time on reload?

How would that look in the frontend, would it call that endpoint every time on reload?

Yes, or at least if not already logged in / if current jwt token is expired. Essentially it's similar to an open-id auth from the frontend's point of view except it 1) is hitting vikunja-backend directly instead of first hitting an external service and 2) it is automatically calling the endpoint instead of waiting for the openid button to be hit.

We can actually make num 2 optional, if for whatever reason we prefer being able to have both IAP login and local/openid logins too.

Yes, or at least if not already logged in / if current jwt token is expired. Essentially it's similar to an open-id auth from the frontend's point of view except it 1) is hitting vikunja-backend directly instead of first hitting an external service and 2) it is automatically calling the endpoint instead of waiting for the openid button to be hit. We can actually make num 2 optional, if for whatever reason we prefer being able to have both IAP login and local/openid logins too.
Owner

Then I'd prefer modifying the existing jwt middleware to accept a jwt token or an IAP header if no token is provided (and move all the logic to create a new user etc there as well). That way, we won't need the new endpoint and can modify the frontend only a bit to make a call to /user every time it is loaded, regardless if it has a jwt token in localstorage or not. I think that would make the IAP a lot more transparent to the frontend.

Then I'd prefer modifying the existing jwt middleware to accept a jwt token or an IAP header if no token is provided (and move all the logic to create a new user etc there as well). That way, we won't need the new endpoint and can modify the frontend only a bit to make a call to `/user` every time it is loaded, regardless if it has a jwt token in localstorage or not. I think that would make the IAP a lot more transparent to the frontend.

Okay, I'll give it a shot.

Okay, I'll give it a shot.

Following up just to make sure I capture the implicit decisions here, so you want for the backend:

  1. If a valid jwt token is presented from the frontend, use that (e.g. ignore the IAP header)
  2. If no valid jwt token exists, create one from the IAP header. In the backend, treat this newly generated jwt token the same as if it was provided by the frontend

In the frontend:

  1. Call /user/token on load -> will get the jwt token generated from the IAP header
Following up just to make sure I capture the implicit decisions here, so you want for the backend: 1. If a valid jwt token is presented from the frontend, use that (e.g. ignore the IAP header) 2. If no valid jwt token exists, create one from the IAP header. In the backend, treat this newly generated jwt token the same as if it was provided by the frontend In the frontend: 1. Call /user/token on load -> will get the jwt token generated from the IAP header
Owner

Almost, I wouldn't generate a jwt token from the backend at all but instead use the IAP header to authenticate the user.

That would look like this in the middleware:

  1. If a valid jwt token is presented from the frontend, use that
  2. If a valid IAP header is present, use that as a means to authenticate the user in place of a jwt token. This includes creating the user internally if none exists yet. There may be a few places which would need to be a bit more abstracted to not only rely on a jwt token to get the user information.

The frontend would then always call user to figure out if the user is authenticated or not. Currently it only does that if a jwt token is present in local storage.

Almost, I wouldn't generate a jwt token from the backend at all but instead use the IAP header to authenticate the user. That would look like this in the middleware: 1. If a valid jwt token is presented from the frontend, use that 2. If a valid IAP header is present, use that as a means to authenticate the user in place of a jwt token. This includes creating the user internally if none exists yet. There may be a few places which would need to be a bit more abstracted to not only rely on a jwt token to get the user information. The frontend would then always call [`user`](https://try.vikunja.io/api/v1/docs#tag/user/paths/~1user/get) to figure out if the user is authenticated or not. Currently it only does that if a jwt token is present in local storage.
skew := time.Minute
if !c.VerifyExpiresAt(now.Add(-skew).Unix(), true) {
delta := now.Sub(time.Unix(c.ExpiresAt, 0))
return fmt.Errorf("token is expired by %v", delta)
Owner

All errors should have a proper type in errors.go. Maybe you could add a new error type ErrorIAPClaimsInvalid and then return that from here for all errors? That would avoid creating 5 different error types for basically the same error.

All errors should have a proper type in `errors.go`. Maybe you could add a new error type `ErrorIAPClaimsInvalid` and then return that from here for all errors? That would avoid creating 5 different error types for basically the same error.
package identityawareproxy
// TODO test GetWebAuth()
Owner

🙂

🙂
var TimeFunc = time.Now
// Caches the public keys of the identity-aware proxy used to validate the auth data it sends
type iapCache struct {
Owner

Please use the keyvalue package for this.

Please use the `keyvalue` package for this.
Owner

I will re-review the frontend PR once this one is ready to merge.

I will re-review the frontend PR once this one is ready to merge.
Owner

Since you unified the external auth providers, could you add some docs about how to add a new auth provider in the future?

Since you unified the external auth providers, could you add some docs about how to add a new auth provider in the future?

Since you unified the external auth providers, could you add some docs about how to add a new auth provider in the future?

I didn't quite pull in openid, since it does something a bit different (there's no continuous checking against the external auth provider), but I can spruce up the docs a bit.

@branchmispredictor I'll give it another review, I just haven't found the time yet.

How is logout handled in general with an IAP?

What about logging the user out?

It's a bit awkward, but it is possible for someone to log out and log in as another user in an IAP. If so, the backend will immediately see the new identity in the IAPClaims. The frontend will not, and will have a JWT cookie pointing to the old identity. There's an if statement to catch this specific case of mismatched identities and raise an error. The next time the frontend gets a new token from /identityawareproxy/token, it will overwrite the old and outdated JWT cookie and then will be fully logged in as a new user.

> Since you unified the external auth providers, could you add some docs about how to add a new auth provider in the future? I didn't quite pull in openid, since it does something a bit different (there's no continuous checking against the external auth provider), but I can spruce up the docs a bit. > @branchmispredictor I'll give it another review, I just haven't found the time yet. > > > How is logout handled in general with an IAP? > > What about logging the user out? It's a bit awkward, but it is possible for someone to log out and log in as another user in an IAP. If so, the backend will immediately see the new identity in the IAPClaims. The frontend will not, and will have a JWT cookie pointing to the old identity. There's an if statement to catch this specific case of mismatched identities and raise an error. The next time the frontend gets a new token from /identityawareproxy/token, it will overwrite the old and outdated JWT cookie and then will be fully logged in as a new user.
Owner

the backend will immediately see the new identity in the IAPClaims. The frontend will not

But wouldn't this only take effect once the page is reloaded? And at that point the frontend will reload everything (lists in the menu etc) so it would change the content and update the state?

> the backend will immediately see the new identity in the IAPClaims. The frontend will not But wouldn't this only take effect once the page is reloaded? And at that point the frontend will reload everything (lists in the menu etc) so it would change the content and update the state?
konrad added 2 commits 2 years ago
46845897d5
Merge branch 'main' into feature/identity-aware-proxy
f75e8fa764
Fix lint
branchmispredictor force-pushed feature/identity-aware-proxy from f75e8fa764 to 8840525b4a 2 years ago

Okay, I've updated the PR to make the IAP middleware more transparent as requested. Now, all the frontend needs to do is call /user/token on refresh and it will get an IAP derived token if there is one.

TODO:

  • Error types instead of strings, document new error num
  • Make the iapCache use keyvalue
Okay, I've updated the PR to make the IAP middleware more transparent as requested. Now, all the frontend needs to do is call `/user/token` on refresh and it will get an IAP derived token if there is one. TODO: - [ ] Error types instead of strings, document new error num - [ ] Make the iapCache use keyvalue
branchmispredictor force-pushed feature/identity-aware-proxy from 8840525b4a to e6af0ac4ee 2 years ago
branchmispredictor force-pushed feature/identity-aware-proxy from e6af0ac4ee to 0c87a9d221 2 years ago
branchmispredictor force-pushed feature/identity-aware-proxy from 0c87a9d221 to 0b82e1ddf3 2 years ago
branchmispredictor force-pushed feature/identity-aware-proxy from 0b82e1ddf3 to 7e92a273eb 2 years ago
branchmispredictor force-pushed feature/identity-aware-proxy from 7e92a273eb to 191261a5cd 2 years ago
branchmispredictor force-pushed feature/identity-aware-proxy from 191261a5cd to f7642b7982 2 years ago
branchmispredictor force-pushed feature/identity-aware-proxy from f7642b7982 to 911dffd8b3 2 years ago
Owner

Oh and by the way, you don't need to force push all the time - I'll squash merge anyway at the end 🙂

Oh and by the way, you don't need to force push all the time - I'll squash merge anyway at the end 🙂
branchmispredictor added 1 commit 2 years ago
575414b329 No need to renew token for IAP
branchmispredictor added 1 commit 2 years ago
213a7db661 fix
branchmispredictor added 1 commit 2 years ago
717c3bcc0b Clean up swagger
branchmispredictor added 1 commit 2 years ago
c9ab22cec7 move to keyvalue

Reviewers

konrad requested changes 2 years ago
Some checks failed
continuous-integration/drone/pr Build is failing
Required
Details
This pull request has changes conflicting with the target branch.
pkg/models/link_sharing.go
pkg/modules/auth/auth.go
pkg/modules/migration/handler/handler.go
.golangci.yml
config.yml.sample
docs/content/doc/setup/config.md
go.sum
go.mod
pkg/modules/auth/openid/openid.go
pkg/routes/api/v1/login.go
Sign in to join this conversation.
No reviewers
No Milestone
No Assignees
2 Participants
Notifications
Due Date

No due date set.

Dependencies

No dependencies set.

Reference: vikunja/api#715
Loading…
There is no content yet.