Skip to content

Commit

Permalink
feat: first working impl with 2 oauth2 apps to support Android login
Browse files Browse the repository at this point in the history
  • Loading branch information
Ks89 committed Jan 9, 2025
1 parent c2fedb2 commit 2ba4547
Show file tree
Hide file tree
Showing 9 changed files with 52 additions and 44 deletions.
2 changes: 1 addition & 1 deletion .env_template
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ HTTP_CORS=true
OAUTH2_CALLBACK=http://localhost:8082/api/callback
OAUTH2_CLIENTID=<GET CLIENTID FOR WEBSITE FROM YOUR GITHUB OAUTH2 APP>
OAUTH2_SECRETID=<GET SECRETID FOR WEBSITE FROM YOUR GITHUB OAUTH2 APP>
OAUTH2_APP_CALLBACK=http://192.168.1.71:8082/api/app_callback
OAUTH2_APP_CALLBACK=http://localhost:8082/api/app_callback
OAUTH2_APP_CLIENTID=<GET CLIENTID FOR APP FROM YOUR GITHUB OAUTH2 APP>
OAUTH2_APP_SECRETID=<GET SECRETID FOR APP FROM YOUR GITHUB OAUTH2 APP>
HTTP_SENSOR_SERVER=http://localhost
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ RUN apk update && apk add --no-cache \
make gcc musl-dev

# install protoc requirements based on https://grpc.io/docs/languages/go/quickstart/
RUN go install google.golang.org/protobuf/cmd/[email protected].1
RUN go install google.golang.org/protobuf/cmd/[email protected].2
RUN go install google.golang.org/grpc/cmd/[email protected]
ENV PATH "$PATH:$(go env GOPATH)/bin"

Expand Down
10 changes: 9 additions & 1 deletion api/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func (handler *Auth) LoginMobileAppCallback(c *gin.Context) {
var jwtKey = []byte(os.Getenv("JWT_PASSWORD"))

profile := c.Value("profile").(models.Profile)
expirationTime := time.Now().Add((60 * time.Minute) * 24 * 30 * 3) // 3 months
expirationTime := time.Now().Add((60 * time.Minute) * 24 * 30 * 6) // 6 months

tokenString, err := utils.CreateJWT(profile, expirationTime, jwt.SigningMethodHS256, jwtKey)
if err != nil {
Expand All @@ -68,7 +68,15 @@ func (handler *Auth) LoginMobileAppCallback(c *gin.Context) {
return
}

cookie, err := c.Request.Cookie("mysession")
if err != nil {
handler.logger.Error("REST - GET - LoginMobileAppCallback - cannot get session cookie from request")
c.JSON(http.StatusInternalServerError, gin.H{"error": "cannot get session cookie"})
return
}

queryParams := url.Values{}
queryParams.Set("session_cookie", cookie.Value)
queryParams.Set("token", tokenString)
location := url.URL{Path: "homeanthill://homeanthill.eu/postlogin", RawQuery: queryParams.Encode()}

Expand Down
2 changes: 1 addition & 1 deletion api/grpc/device/device.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion api/grpc/register/register.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 6 additions & 8 deletions api/login_github.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func (handler *LoginGitHub) GetLoginURL(c *gin.Context) {
}

// OauthAuth function
func (handler *LoginGitHub) OauthAuth(bypassStateCheck bool) gin.HandlerFunc {
func (handler *LoginGitHub) OauthAuth() gin.HandlerFunc {
return func(c *gin.Context) {
// verify if the query param state code matches to one in session
// https://medium.com/keycloak/the-importance-of-the-state-parameter-in-oauth-5419c94bef4c
Expand All @@ -102,13 +102,11 @@ func (handler *LoginGitHub) OauthAuth(bypassStateCheck bool) gin.HandlerFunc {
// The Client should use the content of this parameter to make sure the Code it received matches
// the Authorization Request it sent.
session := sessions.Default(c)
if !bypassStateCheck {
sessionStateB64 := session.Get(handler.sessionStateName)
if sessionStateB64 != c.Query(handler.loginPathStateName) {
handler.logger.Error("OauthAuth - invalid session state: %s ", sessionStateB64)
c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("invalid session state: %s", sessionStateB64))
return
}
sessionStateB64 := session.Get(handler.sessionStateName)
if sessionStateB64 != c.Query(handler.loginPathStateName) {
handler.logger.Error("OauthAuth - invalid session state: %s ", sessionStateB64)
c.AbortWithError(http.StatusInternalServerError, fmt.Errorf("invalid session state: %s", sessionStateB64))
return
}

// read current profile from session.
Expand Down
15 changes: 7 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,19 @@ require (
github.com/natefinch/lumberjack v2.0.0+incompatible
github.com/onsi/ginkgo/v2 v2.22.1
github.com/onsi/gomega v1.36.1
go.mongodb.org/mongo-driver v1.17.1
go.mongodb.org/mongo-driver v1.17.2
go.uber.org/zap v1.27.0
golang.org/x/net v0.33.0
golang.org/x/net v0.34.0
golang.org/x/oauth2 v0.25.0
google.golang.org/grpc v1.69.2
google.golang.org/protobuf v1.36.1
google.golang.org/protobuf v1.36.2
)

require (
github.com/BurntSushi/toml v1.4.0 // indirect
github.com/bytedance/sonic v1.12.6 // indirect
github.com/bytedance/sonic/loader v0.2.1 // indirect
github.com/bytedance/sonic v1.12.7 // indirect
github.com/bytedance/sonic/loader v0.2.2 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
github.com/gin-contrib/sse v1.0.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
Expand Down Expand Up @@ -61,12 +60,12 @@ require (
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.13.0 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/crypto v0.32.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.21.0 // indirect
golang.org/x/tools v0.28.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
29 changes: 14 additions & 15 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic v1.12.6 h1:/isNmCUF2x3Sh8RAp/4mh4ZGkcFAX/hLrzrK3AvpRzk=
github.com/bytedance/sonic v1.12.6/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
github.com/bytedance/sonic v1.12.7 h1:CQU8pxOy9HToxhndH0Kx/S1qU/CuS9GnKYrGioDcU1Q=
github.com/bytedance/sonic v1.12.7/go.mod h1:tnbal4mxOMju17EGfknm2XyYcpyCnIROYOEYuemj13I=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.1 h1:1GgorWTqf12TA8mma4DDSbaQigE2wOgQo7iCjjJv3+E=
github.com/bytedance/sonic/loader v0.2.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/bytedance/sonic/loader v0.2.2 h1:jxAJuN9fOot/cyz5Q6dUuMJF5OqQ6+5GfA8FjjQ0R4o=
github.com/bytedance/sonic/loader v0.2.2/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down Expand Up @@ -161,8 +160,8 @@ github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gi
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM=
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.mongodb.org/mongo-driver v1.17.1 h1:Wic5cJIwJgSpBhe3lx3+/RybR5PiYRMpVFgO7cOHyIM=
go.mongodb.org/mongo-driver v1.17.1/go.mod h1:wwWm/+BuOddhcq3n68LKRmgk2wXzmF6s0SFOa0GINL4=
go.mongodb.org/mongo-driver v1.17.2 h1:gvZyk8352qSfzyZ2UMWcpDpMSGEr1eqE4T793SqyhzM=
go.mongodb.org/mongo-driver v1.17.2/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY=
go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE=
Expand Down Expand Up @@ -191,8 +190,8 @@ golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
Expand All @@ -204,8 +203,8 @@ golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70=
golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
Expand Down Expand Up @@ -256,15 +255,15 @@ golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d h1:xJJRGY7TJcvIlpSrN3K6LAWgNFUILlO+OMAqtg9aqnw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250102185135-69823020774d/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 h1:3UsHvIr4Wc2aW4brOaSCmcxh9ksica6fHEr8P1XhkYw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU=
google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
Expand Down
20 changes: 12 additions & 8 deletions initialization/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,12 @@ func SetupRouter(logger *zap.SugaredLogger) *gin.Engine {

// RegisterRoutes function
func RegisterRoutes(ctx context.Context, router *gin.Engine, logger *zap.SugaredLogger, validate *validator.Validate, client *mongo.Client) {
oauthGithub = api.NewLoginGithub(ctx, logger, client, "oauth2_state", os.Getenv("OAUTH2_CLIENTID"), os.Getenv("OAUTH2_SECRETID"), oauthCallbackURL, oauthScopes)
oauthAppGithub = api.NewLoginGithub(ctx, logger, client, "oauth2_app_state", os.Getenv("OAUTH2_APP_CLIENTID"), os.Getenv("OAUTH2_APP_SECRETID"), oauthAppCallbackURL, oauthScopes)
oauthGithub = api.NewLoginGithub(ctx, logger, client, "oauth2_state",
os.Getenv("OAUTH2_CLIENTID"), os.Getenv("OAUTH2_SECRETID"),
oauthCallbackURL, oauthScopes)
oauthAppGithub = api.NewLoginGithub(ctx, logger, client, "oauth2_app_state",
os.Getenv("OAUTH2_APP_CLIENTID"), os.Getenv("OAUTH2_APP_SECRETID"),
oauthAppCallbackURL, oauthScopes)
auth = api.NewAuth(ctx, logger)

keepAlive = api.NewKeepAlive(ctx, logger)
Expand All @@ -138,15 +142,15 @@ func RegisterRoutes(ctx context.Context, router *gin.Engine, logger *zap.Sugared
router.GET("/api/keepalive", keepAlive.GetKeepAlive)

// 2. Define oAuth2 config to register callbacks
// Attention: if for some reason you'll receive an error in callbacks warning you that the state code in session is missing,
// it's happening because the browser cannot set the session cookie.
// I found this problem using a GitHub oAuth2 callback with a local IP address, instead of 'localhost', while testing
// oAuth2 flow on Android.
oauthGroup := router.Group("/api/callback")
oauthGroup.Use(oauthGithub.OauthAuth(false)) // don't bypass oauth2 state check security feature
oauthGroup.Use(oauthGithub.OauthAuth())
oauthGroup.GET("", auth.LoginCallback)
oauthAppGroup := router.Group("/api/app_callback")
// Attention: in case of local development we want to reach our laptop from the mobile phone via LAN.
// To do this we need to use a local IP address in both `.env` and GitHub oAuth2 app callback.
// However with this setup, a secure cookie won't be set (I don't know why, probably it's related to the redirect made by Giithub server),
// so session will be always empty. To let us develop easily we skip oauth2 state security check on dev/test environments.
oauthAppGroup.Use(oauthAppGithub.OauthAuth(os.Getenv("ENV") != "prod"))
oauthAppGroup.Use(oauthAppGithub.OauthAuth())
oauthAppGroup.GET("", auth.LoginMobileAppCallback)

// 3. Define private APIs (/api group) protected via JWTMiddleware
Expand Down

0 comments on commit 2ba4547

Please sign in to comment.