go-pkgz / auth Goto Github PK
View Code? Open in Web Editor NEWAuthenticator via oauth2, direct, email and telegram
Home Page: https://go-pkgz.umputun.dev/auth/
License: MIT License
Authenticator via oauth2, direct, email and telegram
Home Page: https://go-pkgz.umputun.dev/auth/
License: MIT License
$: 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?
This is going to be another social provider for Microsoft / Azure
Hi! Is it possible to use Multifactor authentication (TOTP, SMS) with this package. Wonderful library!
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)?
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.
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.
see umputun/remark42#707 for details
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.
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:
/[email protected]&name=foo
address
with a customizable message template/login?token=12345
and it will publish auth jwt cookieI 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?
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?
Currently auth supports only personal Microsoft accounts. It'd be nice to also allow work/school accounts from Azure AD to sign in.
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?
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
Line 240 in 2f012ac
However, setting it statically is bad practice and the attribute should be introduced as an option to
Line 52 in 2f012ac
Thinking about something like opts.SameSite
.
Can anybody help implementing this?
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.
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?
@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.
$ 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.
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.
There are probably quite a few parts in this issue, I totally see those as separate small PRs / issues.
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.
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:
Authorization
header)Considerations:
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?Authorization
header should be checked, which is set from the cookie. This kind of gives XSRF protection for free.@Reeywhaar - I have enabled XSRF check and see this:
for sure it was rejected: 2018/12/31 01:14:38 [DEBUG] auth failed, can't get token: xsrf mismatch
and "Protected page contents:" shows Unauthorized
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?
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.
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
I have already partially described the idea in that issue
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.
should be very similar to the regular (public) github provider
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.
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).
Examples server's /private_data
request crashes if oauth login was interrupted.
Steps to reproduce
login with {provider}
/private_data
resetted requestIn 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
Hi there,
When I tried to set opts.AvatarStore to nil, I got a "nil pointer dereference" exception at
Line 75 in dc03f5d
Expected: the original avatar URL should be kept when the avatar proxy is disabled.
Thanks!
Noticed, that although readme tells to use {website}/auth/{prov}/callback
, the code uses {website}/token/{prov}/callback
judging by https://github.com/go-pkgz/auth/blob/master/provider/providers.go and logs.
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.
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
Line 302 in 5784dad
this line seems to suggest that only the header value (default X-XSRF-TOKEN) is checked to see if the token is there.
if the user has not set that header then surely the default cookie value defaultXSRFCookieName = "XSRF-TOKEN"
should be then checked to see if it set and used?
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:
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.
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.
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?
Twitter's auth is a different beast, but it will be nice to have it integrated
This seems to be oauth2 with some extras. See https://developer.apple.com/sign-in-with-apple/
This article adds some explanation as well.
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
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)
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)
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:
https://github.com/go-pkgz/auth/
http://localhost:8080/web/
in a browserLogin with custom123
admin
as usernameadmin
passwordExpectation:
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 inspectinghttp://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.
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.
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.
Hello, I'm trying to configure Remark42 to store avatars in MongoDB, but there are two problems:
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 }, ] }
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
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?
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.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.