Code Monkey home page Code Monkey logo

auth's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

auth's Issues

Add an example service with both minimal backend and frontend

The goal is to make a demo service doing something very simple but demonstrating end-to-end usage of the library.

I'm going to make top-level example directory for this and will have it as a fully automated build producing docker image. The final container with everything in will run somewhere in DO.

@Reeywhaar - how about UI side, can I count on you? Need smth really trivial, maybe a couple of "pages" to demonstrate access to protected resources with login via all providers. If you willing to help I'll give you more details.

Avatar test failure

$ go test github.com/go-pkgz/auth/avatar
2019/04/10 13:22:49 [DEBUG] avatar resize(): limit should be greater than 0
2019/04/10 13:22:49 [DEBUG] saved identicon avatar to b3daa77b4c04a9551b8781d03191fe098f325e67.image, user "user1 name"
2019/04/10 13:22:54 request: /avatar/pic
2019/04/10 13:22:54 [DEBUG] avatar resize(): limit should be greater than 0
2019/04/10 13:22:54 [DEBUG] saved avatar from http://127.0.0.1:33537/pic.png to b3daa77b4c04a9551b8781d03191fe098f325e67.image, user "user1 name"
2019/04/10 13:22:54 can't load avatar - can't load avatar some_random_name.image, id: open /tmp/avatars.test/91/some_random_name.image: no such file or directory - 400 -  - /some_random_name.image [caused by auth/avatar/avatar.go:106 avatar.(*Proxy).Handler]
2019/04/10 13:22:54 [WARN] avatar resize(): reader is nil
2019/04/10 13:22:54 [DEBUG] avatar resize(): limit should be greater than 0
2019/04/10 13:22:54 [WARN] avatar resize(): can't decode avatar image, image: unknown format
2019/04/10 13:22:54 [DEBUG] resizing image is smaller that the limit or has 0 size
2019/04/10 13:22:54 [DEBUG] resizing image is smaller that the limit or has 0 size
2019/04/10 13:22:54 [DEBUG] can't get avatar info 'aaaa', can't load avatar's id for aaaa
2019/04/10 13:22:55 [DEBUG] connect to mongo test instance
2019/04/10 13:22:55 [DEBUG] dial mongo [mongo:27017], ssl=false
2019/04/10 13:23:06 [DEBUG] clean test collection test_78663133
--- FAIL: TestGridFS_PutAndGet (10.94s)
    testing.go:70: no MONGO_TEST in env, defaulted to mongodb://mongo:27017
    testing.go:27: 
            Error Trace:    testing.go:27
                                        once.go:44
                                        testing.go:24
                                        gridfs_test.go:87
                                        gridfs_test.go:17
            Error:          Expected nil, but got: &errors.errorString{s:"can't connect to mongo, no reachable servers"}
            Test:           TestGridFS_PutAndGet
            Messages:       failed to dial
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
    panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x28 pc=0x84cde9]

goroutine 79 [running]:
testing.tRunner.func1(0xc0000e8400)
    /usr/local/go/src/testing/testing.go:830 +0x388
panic(0x8e1ec0, 0xd63990)
    /usr/local/go/src/runtime/panic.go:522 +0x1b5
github.com/go-pkgz/mongo.(*Connection).WithCustomCollection(0xc000363860, 0xc0003644f0, 0xd, 0xc000865e28, 0x1, 0x466332)
    /home/zonescape/go/pkg/mod/github.com/go-pkgz/[email protected]/connection.go:32 +0x29
github.com/go-pkgz/mongo.(*Connection).WithCollection(...)
    /home/zonescape/go/pkg/mod/github.com/go-pkgz/[email protected]/connection.go:26
github.com/go-pkgz/mongo.RemoveTestCollection(0xc0000e8400, 0xc000363860)
    /home/zonescape/go/pkg/mod/github.com/go-pkgz/[email protected]/testing.go:38 +0xd8
github.com/go-pkgz/mongo.MakeTestConnection(0xc0000e8400, 0x2, 0xc000132b18, 0x45d110)
    /home/zonescape/go/pkg/mod/github.com/go-pkgz/[email protected]/testing.go:31 +0x9a
github.com/go-pkgz/auth/avatar.prepGFStore(0xc0000e8400, 0x45d110, 0xc000041f98, 0x4f1999)
    /home/zonescape/go/src2/github.com/go-pkgz/auth/avatar/gridfs_test.go:87 +0x2f
github.com/go-pkgz/auth/avatar.TestGridFS_PutAndGet(0xc0000e8400)
    /home/zonescape/go/src2/github.com/go-pkgz/auth/avatar/gridfs_test.go:17 +0x40
testing.tRunner(0xc0000e8400, 0x988ae8)
    /usr/local/go/src/testing/testing.go:865 +0xc0
created by testing.(*T).Run
    /usr/local/go/src/testing/testing.go:916 +0x357
FAIL    github.com/go-pkgz/auth/avatar  16.641s

PS
Output says something about MongoDB. I don't have MongoDB installed.

Give an access to bearer token, aquired during authentication proccess

In provider/oauth2 the AuthHandler func does receive a brearer-token, using which we could pontentially access a private API of identity provider. Wouldn't it be useful? Any concerns about adding some hook for this?
That way go-pkgz/auth will be used as an authorization framework, allowing to setup a proxy to a private API without giving a client any direct access to bearer-token itself.

Patreon or another donation system

I have already partially described the idea in that issue

umputun/remark42#1034

It would be great to be able to log in through donation services like patreon.

Thus, you can implement the monetization of your project without unnecessary complications. So that only paid subscribers can leave comments.

You could also make a mixture. So that you can log in to paid and free subscribers. But the paid ones would have privileges. For example, somehow highlight their comments. This is especially important for moderators and admins in order to clearly understand who is supporting the project.

You can really think of a lot here.

Optionally send JWT back during login

Currently, the login flow is not friendly for non-web consumers as it sets cookies. However, we already support JWT in non-cookie "transport", i.e. it can be sent as X-JWT header.

In order to simplify the flow we need a way to get JWT back directly as a part of the login sequence.

re: umputun/remark42#787 (comment)

Add verified provider to example app

@Reeywhaar - I have added a new provider to allow self-verified users, i.e. auth with smth like email to deliver confirmation token. This token can be used to login. See #23 for details.

In the demo application, it called "email". Will be nice to have UI support for this provide as you have some time to spend. I think this is as simple as open a box with username and email fields and submit button hits /auth/email/login?user=blah&[email protected]. After the click, it should show another input box asking for confirmation token. The token won't be sent by email, but just printed to stdout. With this token UI should hit /auth/email/login?token=xxxxxx and it will do the usual auth.

Avatar store connection problems

Hello, I'm trying to configure Remark42 to store avatars in MongoDB, but there are two problems:

  1. The mongodb+srv:// URIs are not recognized by NewStore:
func NewStore(uri string) (Store, error) {
        ....
	case strings.HasPrefix(uri, "mongodb://"), strings.HasPrefix(uri, "mongodb+srv://"): // <--- this is missing
        ....
}

just removing the +srv part results in connection failure:

2022/10/02 21:33:31.852 [PANIC] {cmd/server.go:315 cmd.(*ServerCommand).Execute} failed to setup application, failed to make avatar store: failed to connect to mongo server: server selection error: context deadline exceeded, current topology: { Type: Unknown, Servers: [{ Addr: cluster0.abcdef.mongodb.net:27017, Type: Unknown, Last error: connection() error occurred during connection handshake: dial tcp: lookup cluster0.abcdef.mongodb.net: no such host }, ] }

  1. The context timeout of just 1 second is too short:
func NewStore(uri string) (Store, error) {
        ....
	case strings.HasPrefix(uri, "mongodb://"), strings.HasPrefix(uri, "mongodb+srv://"):
                ...
                ctx, cancel := context.WithTimeout(context.Background(), time.Second)
        ....
}

ctx, cancel := context.WithTimeout(context.Background(), time.Second)

resulting in

2022/10/02 22:17:18.812 [PANIC] {cmd/server.go:315 cmd.(*ServerCommand).Execute} failed to setup application, failed to make avatar store: failed to connect to mongo server: timed out while checking out a connection from connection pool: context deadline exceeded; maxPoolSize: 100, connections in use by cursors: 0, connections in use by transactions: 0, connections in use by other operations: 1

I modified the code on the fly by setting ctx, cancel := context.WithTimeout(context.Background(), 30 * time.Second) and it works.
Ideally the timeout should be configurable, MongoDB documentation reports a default timeout of 30 seconds.

Thanks

twitter oauth now required to use oauth2 - unless you have elevated access

As per this statement on twitter's developer website (https://developer.twitter.com/en/docs/twitter-api/getting-started/about-twitter-api):

If you were approved for a developer account before November 15th, 2021, you were automatically converted to Elevated access. This means that your existing Apps can continue to be used to make requests to standard v1.1, premium v1.1, and enterprise endpoints, and that all of your user Access Tokens are still valid.

If you would like to start using v2 endpoints, you will need to attach an App to a Project and use the credentials from that App when making requests to v2 endpoints.

New users are locked in to using oauth2 unless they apply for elevated access, which puts you on a wait list. This conflicts with the existing oauth1 implementation for twitter and I feel that the best way to go forward is to add an oauth2 method for it along with oauth1 so that things don't break for existing users, but allow new users the ability to use twitter easily.

It looks like @nbys was the one who did this pr for adding oauth1 implementation - how easy would it be to add in oauth2? I'm not super familiar with go but I could probably take a stab at it myself, I'm just not sure how to handle the whole "allow both oauth1 and oauth2" debacle.

New opts to pass same site attribute

The SameSite attribute is missing.

About the attribute: https://golang.org/pkg/net/http/#SameSite

Originally I submitted this issue: umputun/remark42#841
It would set the attribute in

jwtCookie := http.Cookie{Name: j.JWTCookieName, Value: tokenString, HttpOnly: true, Path: "/",

However, setting it statically is bad practice and the attribute should be introduced as an option to

type Opts struct {

Thinking about something like opts.SameSite.

Can anybody help implementing this?

Confirmed provider

The goal is to allow some sort of confirmation mechanism to authorize users. It can be used for email confirmation, or slack/telegram or anything else user can reach. The login request will prepare a special "confirmation token", send it to the user and user will leverage it to authenticate into the system.

The typical flow will be:

  1. application hits/[email protected]&name=foo
  2. confirmation token will be sent to given address with a customizable message template
  3. user will use received confirmation token (can be a direct link) to hit /login?token=12345 and it will publish auth jwt cookie

Undocumented parameter for sendConfirmation

Hello!

Lines 141-145 in verify.go (added in #24):

// GET /login?site=site&&user=name&[email protected]
//<...>
Handshake: &token.Handshake{
	State: "",
	From:  r.URL.Query().Get("from"),
	ID:    user + "::" + address,
},

That from field reading is not covered by documentation and is not tested. Readme has different signature listed:

GET /auth/<name>/login?user=<user>&address=<adsress>&aud=<site_id>&from=<url>

It's not clear to me that this "from" URL parameter is send now (as it called just as e.sendConfirmation(w, r) without adding any params), I think code and documentation should be clarified to use it properly or drop it altogether.

Support OpenID and 3rd party IdTokens with cookie-less authentication

There are probably quite a few parts in this issue, I totally see those as separate small PRs / issues.

Context

Currently, auth package supports various OAuth2 providers and acts as a OAuth2 Authorization Server / proxy (without strongly committing to RFC) by issuing self-signed ID tokens based on info provided by /userinfo response, which are passed via a cookie, with extra XSRF protection.

Proposal

Support OpenID providers and ID tokens issued by an external identity provider as authentication tokens. In this scenario, the server won't have private keys and won't issue ID tokens itself. Potentially support OpenID Connect Discovery protocol. Unlike general OAuth2 spec, OpenID supports issuing signed ID tokens bound to a particular user, so these tokens can be used for authentication.

How I see the potential configuration:

    // code below will fetch OpenID Connect Discovery config 
    // from https://accounts.google.com/.well-known/openid-configuration
    // then it'll load keys from "jwks_uri" endpoint and store them under "google" provider
    service.AddOpenIDProvider("google", "https://accounts.google.com", "client-id", "client-secret") 
    
    m := service.Middleware()
    router := chi.NewRouter()

    // setup auth routes
    authRoutes, avaRoutes := service.Handlers()

    // for OpenID providers, /auth handler won't just fetch access token + userinfo, 
    // but will actually request a signed ID token from the provider. 
    // This token can be then passed to the client as is, as it is signed already 
    // and we have public keys for validate it.
    router.Mount("/auth", authRoutes)  // add auth handlers
    router.Mount("/avatar", avaRoutes) // add avatar handler


    // m.OpenIDAuth won't use own keys defined in opts.SecretReader, but instead will use public keys loaded before
    // the provider can be identified either by "iss" claim or manually configured, i.e. m.OpenIDAuth("google")

    // Also, OpenIDAuth shouldn't require a cookie, but Authorization: Bearer <jwt> header to work.
    router.With(m.OpenIDAuth).Get("/api-endpoint", protectedRouteHandler) // protected api

    router.With(m.OpenIDAuth(func(claims token.Claims) bool {
        // do any authorization checks on the token claims, e.g. Role 
    })).Get("/api-endpoint", protectedRouteHandler) // protected api

With OpenIDAuth authentication middleware, the server should act as a OAuth2 Resource Server, i.e. to expect Authorization: Bearer <jwt> header and use that for authentication.

Having this would allow:

  • Remove need in issuing auth (ID) tokens, as well as managing signing keys
  • Easy integration with new providers
  • Unify user / API authentication middleware (by using Authorization header)
  • Multiple services using the same auth middleware configuration without sharing secrets

Considerations:

  • Some parts of configuration options are irrelevant for OpenID providers, where auth is only acting as a authentication proxy basically. Like opts.ClaimsUpdater won't work - since we don't have private keys, we can't modify claims. Probably OpenID should have own configuration options?
  • How to pass a signed ID token to the client? I think the cookie approach can still be used, but instead of checking the cookie, Authorization header should be checked, which is set from the cookie. This kind of gives XSRF protection for free.

Add Mastodon?

In the light of the exodus from Twitter to Mastodon maybe it could be worth doing a push and implementing Mastodon as a provider?

I have only done a little Go last couple of years but could take a look at it if it is of interest (and if I could get some help along the way if necessary).

Note: I come here from umputun/remark42#477

Password in GET is Insecure

From the README:

GET /auth//login?user=&passwd=&aud=<site_id>&session=[1|0]

this is insecure!

GET requests logged, which reveals the password to everybody who has access to the logs.

Please don't support this insecure way.

[Q] Why don't we use refresh token?

In current implementation we refresh token if it's valid and expired, but what's point to refresh token without dividing on access and refresh tokens?
The reason of refreshing is to set access token expiration time to low and getting new with refresh token to not compromising security. But now if token will be compromised it can be refreshed(so user will always be logged in). It was done intentionally and I don't understand something or It's not implemented yet(if so I would like to contribute)?

Request more than one info url

After authentication with my provider (GitHub) I would like to fill the token.User with additional info like the organizations/teams they are in to allow RBAC later on. Unfortunately, it seems like the access token is only used to retrieve the infoURL and avatar and is discarded afterwards.

Is there some functionality in this to use the access token to do another request in MapUserFn or ClaimsUpd? If not, do you think it would be possible to add another hook for this? Something like

GetUserInfoFn(client *http.Client) provider.UserData

that would by default do the current implementation

uinfo, err := client.Get(p.infoURL) 

but could be overridden with a custom implementation?

Public method for self-implemented auth handler

As we discussed in #54, the idea is to add a public method to append self-implemented auth handler to stack of usual handlers. It would be helpful in order to use this library with some strange providers (e.g. Telegram)

Authentication cookies not readable on localhost

I have hosted my go based direct oauth login server at localhost:9999

My frontend server is running at localhost:3000, I am able to hit /oauth/local/login api from my browser successfully, but it doesn't populate cookies in any further requests.

I tried lots of solutions on google, most of them are pointing to enable credentials in header. I did try to set these paramerters in my header response:

		responseWriter.Header().Set("Access-Control-Expose-Headers", "XSRF-TOKEN")
		responseWriter.Header().Set("Access-Control-Allow-Origin", "localhost:9999, localhost, localhost:3000")
		responseWriter.Header().Set("Access-Control-Allow-Credentials", "true")

But it still doesn't work. Any idea on what I am missing here? Do I have to enable some flag in auth library?

PS: It's working fine if I serve frontend files from my go server directly.

Telegram auth panics in remark42

I've started remark42 with AUTH_TELEGRAM=true and TELEGRAM_TOKEN set in compose-dev-frontend.yml, and when I open http://127.0.0.1:8080/auth/telegram/login I get 500 Internal Server Error once and then calls to that endpoint just times out. Backend logs:

2021/08/05 16:54:36.806 [INFO]  {logger/logger.go:130 logger.(*Middleware).Handler.func1.1} GET - /auth/telegram/login - 127.0.0.1 - 81c21ca5009d - 200 (0) - 76.125µs
2021/08/05 16:54:36.806 [INFO]  {rest/middleware.go:62 rest.Recoverer.func1.1.1} request panic for /auth/telegram/login from 172.23.0.1:58176, assignment to entry in nil map
2021/08/05 16:54:36.806 [INFO]  {rest/middleware.go:64 rest.Recoverer.func1.1.1} goroutine 34 [running]:
runtime/debug.Stack(0x40000d4180, 0xc6acbe, 0x20)
 /usr/local/go/src/runtime/debug/stack.go:24 +0x88
github.com/go-pkgz/rest.Recoverer.func1.1.1(0xffff5ef669b8, 0x40000d4180, 0x400063a800, 0x11da270, 0x400094a0e0)
 /build/backend/vendor/github.com/go-pkgz/rest/middleware.go:64 +0x198
panic(0xacc220, 0x11b8b70)
 /usr/local/go/src/runtime/panic.go:965 +0x154
github.com/go-pkgz/auth/provider.(*TelegramHandler).LoginHandler(0x400064f0e0, 0x11d9b20, 0x4000596ee0, 0x400063a900)
 /build/backend/vendor/github.com/go-pkgz/auth/provider/telegram.go:198 +0x71c
github.com/go-pkgz/auth/provider.Service.Handler(0x11dd408, 0x400064f0e0, 0x11d9b20, 0x4000596ee0, 0x400063a900)
 /build/backend/vendor/github.com/go-pkgz/auth/provider/service.go:60 +0x208
github.com/go-pkgz/auth.(*Service).Handlers.func1(0x11d9b20, 0x4000596ee0, 0x400063a900)
 /build/backend/vendor/github.com/go-pkgz/auth/auth.go:199 +0x51c
net/http.HandlerFunc.ServeHTTP(0x400091b890, 0x11d9b20, 0x4000596ee0, 0x400063a900)
 /usr/local/go/src/net/http/server.go:2069 +0x40
github.com/go-chi/chi/v5.(*Mux).Mount.func1(0x11d9b20, 0x4000596ee0, 0x400063a900)
 /build/backend/vendor/github.com/go-chi/chi/v5/mux.go:314 +0x170
net/http.HandlerFunc.ServeHTTP(0x4000596500, 0x11d9b20, 0x4000596ee0, 0x400063a900)
 /usr/local/go/src/net/http/server.go:2069 +0x40
github.com/go-chi/chi/v5/middleware.NoCache.func1(0x11d9b20, 0x4000596ee0, 0x400063a900)
 /build/backend/vendor/github.com/go-chi/chi/v5/middleware/nocache.go:54 +0x248
net/http.HandlerFunc.ServeHTTP(0x400047e378, 0x11d9b20, 0x4000596ee0, 0x400063a900)
 /usr/local/go/src/net/http/server.go:2069 +0x40
github.com/didip/tollbooth_chi.(*limiterWrapper).ServeHTTP(0x400047e390, 0x11d9b20, 0x4000596ee0, 0x400063a900)
 /build/backend/vendor/github.com/didip/tollbooth_chi/tollbooth_chi.go:41 +0x250
github.com/go-pkgz/rest/logger.(*Middleware).Handler.func1(0x11da270, 0x400094a0e0, 0x400063a900)
 /build/backend/vendor/github.com/go-pkgz/rest/logger/logger.go:133 +0x17c
net/http.HandlerFunc.ServeHTTP(0x40009303c0, 0x11da270, 0x400094a0e0, 0x400063a900)
 /usr/local/go/src/net/http/server.go:2069 +0x40
github.com/go-chi/chi/v5/middleware.Timeout.func1.1(0x11da270, 0x400094a0e0, 0x400063a800)
 /build/backend/vendor/github.com/go-chi/chi/v5/middleware/timeout.go:45 +0x17c
net/http.HandlerFunc.ServeHTTP(0x4000596560, 0x11da270, 0x400094a0e0, 0x400063a800)
 /usr/local/go/src/net/http/server.go:2069 +0x40
github.com/go-chi/chi/v5.(*ChainHandler).ServeHTTP(0x40005e9840, 0x11da270, 0x400094a0e0, 0x400063a800)
 /build/backend/vendor/github.com/go-chi/chi/v5/chain.go:31 +0x4c
github.com/go-chi/chi/v5.(*Mux).routeHTTP(0x4000431d40, 0x11da270, 0x400094a0e0, 0x400063a800)
 /build/backend/vendor/github.com/go-chi/chi/v5/mux.go:442 +0x250
net/http.HandlerFunc.ServeHTTP(0x400091b8b0, 0x11da270, 0x400094a0e0, 0x400063a800)
 /usr/local/go/src/net/http/server.go:2069 +0x40
github.com/go-chi/cors.(*Cors).Handler.func1(0x11da270, 0x400094a0e0, 0x400063a800)
 /build/backend/vendor/github.com/go-chi/cors/cors.go:228 +0x19c
net/http.HandlerFunc.ServeHTTP(0x40005964c0, 0x11da270, 0x400094a0e0, 0x400063a800)
 /usr/local/go/src/net/http/server.go:2069 +0x40
github.com/go-pkgz/rest.Ping.func1(0x11da270, 0x400094a0e0, 0x400063a800)
/build/backend/vendor/github.com/go-pkgz/rest/middleware.go:51 +0x74
net/http.HandlerFunc.ServeHTTP(0x400047e2a0, 0x11da270, 0x400094a0e0, 0x400063a800)
 /usr/local/go/src/net/http/server.go:2069 +0x40
github.com/go-pkgz/rest.AppInfo.func1.1(0x11da270, 0x400094a0e0, 0x400063a800)
 /build/backend/vendor/github.com/go-pkgz/rest/middleware.go:34 +0x31c
net/http.HandlerFunc.ServeHTTP(0x400091c190, 0x11da270, 0x400094a0e0, 0x400063a800)
 /usr/local/go/src/net/http/server.go:2069 +0x40
github.com/go-pkgz/rest.Recoverer.func1.1(0x11da270, 0x400094a0e0, 0x400063a800)
 /build/backend/vendor/github.com/go-pkgz/rest/middleware.go:69 +0x98
net/http.HandlerFunc.ServeHTTP(0x4000930150, 0x11da270, 0x400094a0e0, 0x400063a800)
 /usr/local/go/src/net/http/server.go:2069 +0x40
github.com/go-chi/chi/v5/middleware.RealIP.func1(0x11da270, 0x400094a0e0, 0x400063a800)
 /build/backend/vendor/github.com/go-chi/chi/v5/middleware/realip.go:34 +0x88
net/http.HandlerFunc.ServeHTTP(0x400047e2b8, 0x11da270, 0x400094a0e0, 0x400063a800)
 /usr/local/go/src/net/http/server.go:2069 +0x40
github.com/go-chi/chi/v5/middleware.ThrottleWithOpts.func1.1(0x11da270, 0x400094a0e0, 0x400063a800)
 /build/backend/vendor/github.com/go-chi/chi/v5/middleware/throttle.go:100 +0x410
net/http.HandlerFunc.ServeHTTP(0x40005e9200, 0x11da270, 0x400094a0e0, 0x400063a800)
 /usr/local/go/src/net/http/server.go:2069 +0x40
github.com/go-chi/chi/v5.(*Mux).ServeHTTP(0x4000431d40, 0x11da270, 0x400094a0e0, 0x40003b5b00)
 /build/backend/vendor/github.com/go-chi/chi/v5/mux.go:88 +0x284
net/http.serverHandler.ServeHTTP(0x400094a000, 0x11da270, 0x400094a0e0, 0x40003b5b00)
 /usr/local/go/src/net/http/server.go:2887 +0xbc
net/http.(*conn).serve(0x40008ea000, 0x11dd280, 0x40003e3780)
 /usr/local/go/src/net/http/server.go:1952 +0x71c
created by net/http.(*Server).Serve
 /usr/local/go/src/net/http/server.go:3013 +0x318

2fa support

Hi! Is it possible to use Multifactor authentication (TOTP, SMS) with this package. Wonderful library!

Auth status handler panics if user didn't finish the auth process

Hello. First of all, thank you for this awesome lib.

Version: master (v1.18.1-0.20211209053423-949213843b23)

Problem: If the user doesn't finish auth process and return to the previous page:
handler /auth/user returns status 200 and null as a response body
handler /auth/status panics

http: panic serving 127.0.0.1:63736: runtime error: invalid memory address or nil pointer dereference
goroutine 704 [running]:
net/http.(*conn).serve.func1()
        /usr/local/Cellar/go/1.17.6/libexec/src/net/http/server.go:1802 +0xb9
panic({0x2057a40, 0x2f9e580})
        /usr/local/Cellar/go/1.17.6/libexec/src/runtime/panic.go:1047 +0x266
github.com/go-pkgz/auth.(*Service).Handlers.func1({0x2b539438, 0xc0007be780}, 0xc0005b3f00)
        /Users/dv/go/pkg/mod/github.com/go-pkgz/[email protected]/auth.go:199 +0x5ed
net/http.HandlerFunc.ServeHTTP(0xc, {0x2b539438, 0xc0007be780}, 0xc0008c0f8a)
        /usr/local/Cellar/go/1.17.6/libexec/src/net/http/server.go:2047 +0x2f
github.com/go-chi/chi/v5.(*Mux).Mount.func1({0x2b539438, 0xc0007be780}, 0xc0005b3f00)
        /Users/dv/go/pkg/mod/github.com/go-chi/chi/[email protected]/mux.go:314 +0x19c
net/http.HandlerFunc.ServeHTTP(0x204d4a0, {0x2b539438, 0xc0007be780}, 0xc0008c0f84)
        /usr/local/Cellar/go/1.17.6/libexec/src/net/http/server.go:2047 +0x2f
github.com/go-chi/chi/v5.(*Mux).routeHTTP(0xc00046cae0, {0x2b539438, 0xc0007be780}, 0xc0005b3f00)
        /Users/dv/go/pkg/mod/github.com/go-chi/chi/[email protected]/mux.go:442 +0x216
net/http.HandlerFunc.ServeHTTP(0xc00032a280, {0x2b539438, 0xc0007be780}, 0xc0005b3f00)
        /usr/local/Cellar/go/1.17.6/libexec/src/net/http/server.go:2047 +0x2f
github.com/go-chi/cors.(*Cors).Handler.func1({0x2b539438, 0xc0007be780}, 0xc0005b3f00)
        /Users/dv/go/pkg/mod/github.com/go-chi/[email protected]/cors.go:228 +0x1bd
net/http.HandlerFunc.ServeHTTP(0xc0005b3e00, {0x2b539438, 0xc0007be780}, 0x1000000000000d0)
        /usr/local/Cellar/go/1.17.6/libexec/src/net/http/server.go:2047 +0x2f
github.com/go-chi/chi/v5/middleware.RequestLogger.func1.1({0x2493fa0, 0xc000656620}, 0xc0005b3e00)
        /Users/dv/go/pkg/mod/github.com/go-chi/chi/[email protected]/middleware/logger.go:57 +0x18e
net/http.HandlerFunc.ServeHTTP(0x24984d8, {0x2493fa0, 0xc000656620}, 0x2f9dff0)
        /usr/local/Cellar/go/1.17.6/libexec/src/net/http/server.go:2047 +0x2f
github.com/go-chi/chi/v5.(*Mux).ServeHTTP(0xc00046cae0, {0x2493fa0, 0xc000656620}, 0xc0005b3c00)
        /Users/dv/go/pkg/mod/github.com/go-chi/chi/[email protected]/mux.go:88 +0x442
net/http.serverHandler.ServeHTTP({0xc0007a19e0}, {0x2493fa0, 0xc000656620}, 0xc0005b3c00)
        /usr/local/Cellar/go/1.17.6/libexec/src/net/http/server.go:2879 +0x43b
net/http.(*conn).serve(0xc0002a0dc0, {0x2498580, 0xc0003fb0b0})
        /usr/local/Cellar/go/1.17.6/libexec/src/net/http/server.go:1930 +0xb08
created by net/http.(*Server).Serve
        /usr/local/Cellar/go/1.17.6/libexec/src/net/http/server.go:3034 +0x4e8

Steps to reproduce:

  1. Start auth with Google provider.
  2. After being redirected to a "Choose an account" screen, return without choosing anything.

Example build error

$: cd _example
$: go run main.go
# command-line-arguments
./main.go:82:51: undefined: "github.com/go-pkgz/rest/logger".WithBody

Something wrong with go.mod? Btw, does this project have to be in $GOROOT?

Common shared secret

Currently, there is a fundamental limitation in a way secret used. Even with secret reader injected into the token package, it is impossible to use different secrets for different aud values.

In some complex use cases having different secrets will be desirable. For example, if some service issuing tokens for various services or a different group of users, it may be useful to have different keys (secrets) used for withing each group to sigin and verify token.

Currently, it is impossible to do because aud is a part of the claim, and to extract it from jwt without disabling signature validation, this key should be known before the parsing step. In other words, we can make tokens with a custom (per aud) secret, but we can't parse them without the real secret.

I don't like the idea of the pre-parsing token without signature verification (jwt.ParseUnverified can do it) to extract aud first. I'm not sure what issues it may cause, but it feels unusual and (potentially) not secure.

I am trying to figure an alternative method of achieving the goal, i.e. ability to have a secret per aud.

[Q] Check if user exists before generating JWT token

This is more of a questionnaire thread rather than a bug report.

I am trying to use go-pkz for my application. I have integrated github and google as providers. I have few doubts and would be grateful if someone can answer these..

  • Can we fetch email also from google and github provider and update in claim token (as of now it have name, id and avatar only)?
    It looks like I can use ClaimsUpdater to fetch email and store it in token. Would that be correct way?

  • What's the best location to check whether user account exists in our platform or not? I was thinking it might be Validator, but validator is invoked at every call. Any tips on how can I optimize it? Maybe just check once, while generating JWT token using provided secret?

Thanks for any help

NoOp implementation not include in latest release

I need use NoOp for disable avatar support. I see it implemented in package, but when I try package update using go get -u it feature (noop.go) missing in latest release.

Could you update release for NoOp support?

/auth prefix hardcoded in providers

The example and documentation show mount like this: router.Mount("/auth", authRoutes) however attempt to change "/auth" path to smth else not really supported due to provider's callback urls.

This may cause confusion and should be addressed somehow.

Support twitter auth

Twitter's auth is a different beast, but it will be nice to have it integrated

Bug: (/_example) Using "Login with custom_123" results in "Invalid Request"

Thanks for all the great work on this library.

This is my first issue, so apologies if I've missed the mark or omitted something. Constructive criticism is appreciated.

Version: master v1.18.0
Browser: Chrome Version 106.0.5249.103 (Official Build) (64-bit)

Problem: When running the example and choosing "Login with custom_123", entering the credentials provided results in an invalid request.

Steps:

  • git clone https://github.com/go-pkgz/auth/
  • cd /auth/_example
  • go mod tidy
  • go run main.go
  • open http://localhost:8080/web/ in a browser
  • click Login with custom123
  • enter admin as username
  • enter admin password
  • click authorize

Expectation:

You are redirected to http://localhost:8080/web/ and are authorized using the custom provider

Result:

"Invalid Request"

Notes:

Replacing the action attribute of the form element present on http://127.0.0.1:9096/authorize.. with a URL decoded version results in success.

This is what the

element looks like when inspecting http://127.0.0.1:9096/authorize... (the custom oauth2 server)

<form action="/login/oauth/authorize?client_id%3dcid%26redirect_uri%3dhttp%253A%252F%252Flocalhost%253A8080%252Fauth%252Fcustom123%252Fcallback%26response_type%3dcode%26state%3dd11e3e82d573eb897c28e8ed47f5798c791e15b5" method="POST">

If I edit the action attribute and and decode it via https://meyerweb.com/eric/tools/dencoder/

I get the following:

/login/oauth/authorize?client_id=cid&redirect_uri=http%3A%2F%2Flocalhost%3A8080%2Fauth%2Fcustom123%2Fcallback&response_type=code&state=d11e3e82d573eb897c28e8ed47f5798c791e15b5

If I replace the original form action with the above then the form submission works as expected.

Generate identicon avatars

In case if auth provider doesn't have pictures (for example direct providers) we should generate identicon. This is not a new dependency as it uses by dev server already.

Unable to access XSRF cookie from chrome plugin

I have a chrome extension as frontend for my application. I am unable to get XSRF-TOKEN cookie from this extension.

It works fine, if I host a web frontend on same domain with my backend server. But if I try to do the same from chrome plugin, it's not able to access the cookie. Maybe it's because of some cross site protection? Do we have any flag to disable such kind of protection?

Ability to increase scopes without copy pasting a lot of code

Since the current scopes are limited to name, id and avatar, adding an email scope requires copying & pasting a lot of code for each provider, but of course I can be wrong.

auth.go:

p := provider.Params{
	URL:         s.opts.URL,
	JwtService:  s.jwtService,
	Issuer:      s.issuer,
	AvatarSaver: s.avatarProxy,
	Cid:         cid,
	Csecret:     csecret,
	L:           s.logger,
}

    ...
case "google":
	s.providers = append(s.providers, provider.NewService(provider.NewGoogle(p)))

Using this feels a lot verbose, is this a good idea to allow scopes as a parameter?

Multiple refreshes for expired token

Currently, token refresh can be triggered by multiple queries depends on UI usage. If UI accessing multiple protected resources at the same time each call will cause a refresh.

Logically this is not a problem, however, it can be optimized to eliminate multiple potentially heavy calls (token refresh may involve custom ClaimsUpdater with some trips to DB or another store). The simplest way to do it is to invoke refresh not on the fully expired token, but in a few random milliseconds prior to token expiration. In this case, we will reduce (hopefully significantly) the number of unnecessary refreshes.

Compilation error with rest package v.1.6.0

I tried use the auth v.1.14.0 in my new project and get compilation error:

***\go\pkg\mod\github.com\go-pkgz\[email protected]\provider\direct.go:124:17: too many arguments in call to rest.RenderJSON
	have (http.ResponseWriter, *http.Request, *token.User)
	want (http.ResponseWriter, interface {})
***\go\pkg\mod\github.com\go-pkgz\[email protected]\provider\oauth1.go:163:17: too many arguments in call to rest.RenderJSON
	have (http.ResponseWriter, *http.Request, *token.User)
	want (http.ResponseWriter, interface {})
***\go\pkg\mod\github.com\go-pkgz\[email protected]\provider\oauth2.go:214:17: too many arguments in call to rest.RenderJSON
	have (http.ResponseWriter, *http.Request, *token.User)
	want (http.ResponseWriter, interface {})
***\go\pkg\mod\github.com\go-pkgz\[email protected]\provider\telegram.go:202:18: too many arguments in call to rest.RenderJSON
	have (http.ResponseWriter, *http.Request, struct { Token string "json:\"token\""; Bot string "json:\"bot\"" })
	want (http.ResponseWriter, interface {})
***\go\pkg\mod\github.com\go-pkgz\[email protected]\provider\telegram.go:249:17: too many arguments in call to rest.RenderJSON
	have (http.ResponseWriter, *http.Request, *token.User)
	want (http.ResponseWriter, interface {})
***\go\pkg\mod\github.com\go-pkgz\[email protected]\provider\verify.go:130:17: too many arguments in call to rest.RenderJSON
	have (http.ResponseWriter, *http.Request, *token.User)
	want (http.ResponseWriter, interface {})
***\go\pkg\mod\github.com\go-pkgz\[email protected]\provider\verify.go:192:17: too many arguments in call to rest.RenderJSON
	have (http.ResponseWriter, *http.Request, rest.JSON)
	want (http.ResponseWriter, interface {})

I researched errors and find incompatible dependency in the auth package with rest package v.1.6.0.
Since this version method RenderJSON has two incoming parameters instead three as previously versions.
In the auth package dependency for rest package set as v1.5.0

Because I use you rest package outside auth package, new version rest package was fetch to list in go.mod
Are you will plan fix this in the near future?

Cannot disable avatar support

Hi there,

When I tried to set opts.AvatarStore to nil, I got a "nil pointer dereference" exception at

avatarURL, e := ava.Put(u, client)

Looks like this is a bug when "nil" of avatar.Proxy is not nil anymore when implicitly cast to AvatarSaver

image

Expected: the original avatar URL should be kept when the avatar proxy is disabled.

Thanks!

Add support of custom oauth2 server

The goal is to allow passing of go-oauth2/oauth2 as a special kind of provider, start the server and route request accordingly. Probably it will also allow removing the current dev provider (will be replaced by go-oauth2/oauth2 based one).

[Q] Using go-pkgz/auth for authenticating mobile apps

I'd like to use go-pkgz/auth to authenticate a mobile app, however it's unclear what's the best way to do that. Some best practices are discussed here: https://auth0.com/blog/oauth-2-best-practices-for-native-apps/

Thus it would seem that it's best to
(1) use the native web browser to perform the login
(2) change the redirect_uri code in go-pkgz/auth to append an authorization code parameter (maybe if required?) and ensure the redirect_uri is sent to my app on iOS and Android
(3) add the authorization code as an alternative way to authenticate with /user/auth
(4) query with GET /auth/user path with the authorization code e.g. in header (X-Authorization)
(5) /auth/user then replies with the X-JWT cookie which I can grab (since this request is not made in the web view)

The Authorization code should probably be only valid for a very short time as the flow is automatic.

The above seems to require changes to the lib and a lot of integration work. Is there a simpler solution involving go-pkgz/auth?

Example server crashes on login abort

Examples server's /private_data request crashes if oauth login was interrupted.

Steps to reproduce

  • start example
  • navigate to http://127.0.0.1:8080/web
  • click on any login with {provider}
  • close the popped up tab/page without granting access
  • refresh main page
  • you'll see that iframe with /private_data resetted request

In logs you can see:

auth-example    | 2018/12/29 04:56:12 [REST] GET - /private_data - 192.168.48.1 - 200 (0) - 195.9µs
auth-example    | 2018/12/29 04:56:12 http: panic serving 192.168.48.1:59624: runtime error: invalid memory address or nil pointer dereference
auth-example    | goroutine 42 [running]:
auth-example    | net/http.(*conn).serve.func1(0xc000140dc0)
auth-example    |       /usr/local/go/src/net/http/server.go:1746 +0xd0
auth-example    | panic(0x82f9e0, 0xbf8f90)
auth-example    |       /usr/local/go/src/runtime/panic.go:513 +0x1b9
auth-example    | github.com/go-pkgz/auth/middleware.(*Authenticator).auth.func2.1(0x922fc0, 0xc0001a3dc0, 0xc0001c6d00)
auth-example    |       /go/pkg/mod/github.com/go-pkgz/[email protected]/middleware/auth.go:88 +0x6ad
auth-example    | net/http.HandlerFunc.ServeHTTP(0xc000069920, 0x922fc0, 0xc0001a3dc0, 0xc0001c6d00)
auth-example    |       /usr/local/go/src/net/http/server.go:1964 +0x44
auth-example    | github.com/go-chi/chi.(*ChainHandler).ServeHTTP(0xc0000aeac0, 0x922fc0, 0xc0001a3dc0, 0xc0001c6d00)
auth-example    |       /go/pkg/mod/github.com/go-chi/[email protected]+incompatible/chain.go:31 +0x52
auth-example    | github.com/go-chi/chi.(*Mux).routeHTTP(0xc0000826c0, 0x922fc0, 0xc0001a3dc0, 0xc0001c6d00)
auth-example    |       /go/pkg/mod/github.com/go-chi/[email protected]+incompatible/mux.go:424 +0x239
auth-example    | github.com/go-chi/chi.(*Mux).routeHTTP-fm(0x922fc0, 0xc0001a3dc0, 0xc0001c6d00)
auth-example    |       /go/pkg/mod/github.com/go-chi/[email protected]+incompatible/mux.go:368 +0x48
auth-example    | net/http.HandlerFunc.ServeHTTP(0xc0000673f0, 0x922fc0, 0xc0001a3dc0, 0xc0001c6d00)
auth-example    |       /usr/local/go/src/net/http/server.go:1964 +0x44
auth-example    | github.com/go-pkgz/rest/logger.(*Middleware).Handler.func1(0x923580, 0xc00013cfc0, 0xc0001c6d00)
auth-example    |       /go/pkg/mod/github.com/go-pkgz/[email protected]/logger/logger.go:93 +0x1cc
auth-example    | net/http.HandlerFunc.ServeHTTP(0xc0000729c0, 0x923580, 0xc00013cfc0, 0xc0001c6d00)
auth-example    |       /usr/local/go/src/net/http/server.go:1964 +0x44
auth-example    | github.com/go-pkgz/rest.Ping.func1(0x923580, 0xc00013cfc0, 0xc0001c6d00)
auth-example    |       /go/pkg/mod/github.com/go-pkgz/[email protected]/middleware.go:40 +0x68
auth-example    | net/http.HandlerFunc.ServeHTTP(0xc0000729e0, 0x923580, 0xc00013cfc0, 0xc0001c6d00)
auth-example    |       /usr/local/go/src/net/http/server.go:1964 +0x44
auth-example    | github.com/go-pkgz/rest.AppInfo.func1.1(0x923580, 0xc00013cfc0, 0xc0001c6d00)
auth-example    |       /go/pkg/mod/github.com/go-pkgz/[email protected]/middleware.go:21 +0x1c3
auth-example    | net/http.HandlerFunc.ServeHTTP(0xc000092410, 0x923580, 0xc00013cfc0, 0xc0001c6d00)
auth-example    |       /usr/local/go/src/net/http/server.go:1964 +0x44
auth-example    | github.com/go-chi/chi.(*Mux).ServeHTTP(0xc0000826c0, 0x923580, 0xc00013cfc0, 0xc0001c6c00)
auth-example    |       /go/pkg/mod/github.com/go-chi/[email protected]+incompatible/mux.go:81 +0x293
auth-example    | net/http.serverHandler.ServeHTTP(0xc00006f450, 0x923580, 0xc00013cfc0, 0xc0001c6c00)
auth-example    |       /usr/local/go/src/net/http/server.go:2741 +0xab
auth-example    | net/http.(*conn).serve(0xc000140dc0, 0x923a40, 0xc0001b8580)
auth-example    |       /usr/local/go/src/net/http/server.go:1847 +0x646
auth-example    | created by net/http.(*Server).Serve
auth-example    |       /usr/local/go/src/net/http/server.go:2851 +0x2f5

Failed avatar request should fallback to auto-gen avatar

We already support identicon avatar in case if provider returns no info about the picture. However, for some providers this is impossible to know before we do the actual request, one such example is MS, where we get avatar as a separate call to "https://graph.microsoft.com/beta/me/photo/$value"

The simplest solution is to handle avatar's load call the same way as we do in the case of an empty Picture claim

This is the relevant error:

remark42.linux-amd64[153733]: 2021/05/07 13:27:51.901 [INFO]  {rest/httperrors.go:39 rest.SendErrorJSON} failed to save avatar to proxy - failed to save avatar for: failed to fetch avatar from the orig: failed to get avatar from the orig, status 404 Not Found - 500 - 1.1.1.1 - /auth/microsoft/callback?code=xxxxxx&state=yyyyyy [caused by auth/provider/oauth2.go:185 provider.Oauth2Handler.AuthHandler]

related to umputun/remark42#978 (reply in thread)

Telegram auth doesn't set "aud" in JWT token after login

Telegram login method doesn't set "aud" in generated JWT token which prevents it from being used in remark42. Example JWT token with Telegram auth:

{
  "exp": 1629041975,
  "jti": "5dfe954c0d62d41f5722b2cfdce6242a8fe32b4b",
  "iat": 1629041675,
  "iss": "telegram",
  "user": {
    "name": "Ksenia",
    "id": "telegram_d1660f94f72ab7e578766460c7004e95607fb586",
    "picture": "http://127.0.0.1:8080/api/v1/avatar/f6c6df0ddfcae25b1358c87e1af9904208837983.image",
    "attrs": {
      "admin": false,
      "blocked": false
    }
  }
}

With anonymous auth:

{
  "aud": "remark",
  "exp": 1629041567,
  "jti": "eafedda197100f969b902ff79a441d72dabaa852",
  "iat": 1629041267,
  "iss": "remark42",
  "user": {
    "name": "test",
    "id": "anonymous_a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
    "picture": "http://127.0.0.1:8080/api/v1/avatar/c5f426697ad14b7fe76e2b154e89c5b6cbc24b61.image",
    "attrs": {
      "admin": false,
      "blocked": false
    }
  }
}

Is it something related with this package @holykol?

Proporsal: way to modify Claims during auth process

What do you think about something like ClaimsUpd, but for auth process, for tokens received from clients?

When it could be useful: modifying Claims by internal logic.
For example it would be convenient to give admins rights for users with ID from list.

But on the other hand adding this feature will separate token received from client and Claims presentation, that's why this might be not really good idea.

Admin user hasn't admin role

I use RBAC middleware in my project and when i wrote unit test for rest handler (which wrap in RBAC) my test fall. In test I use basic auth, but var adminUser in auth.go hasn't assigned with admin role.

// adminUser sets claims for an optional basic auth
var adminUser = token.User{
	ID:   "admin",
	Name: "admin",
        Role: "admin",   // <-- add this
	Attributes: map[string]interface{}{
		"admin": true,
	},

}

I suppose if admin flag set true his role have to admin too.

Could you fix it? If are you hasn't free time i will fix and make PR.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.