I’m integrating an internal SSO (OAuth2) into a web application using Gin (Go), and I’m a bit unsure about the right place to create the application session.

The SSO is the only authentication mechanism (no local username/password). The frontend simply redirects users to the backend, and the backend handles the OAuth flow.

Current flow:

  1. User clicks Login on the frontend

  2. Frontend redirects to /auth/sso/login

  3. Backend redirects the user to the internal SSO

  4. SSO redirects back to /auth/sso/callback with code and state

  5. Backend exchanges the code for an access_token

  6. Backend redirects again to /auth/sso/connect

  7. /auth/sso/connect uses the token to fetch user info and then creates the session

here is the handler where i currently create the session:

func (h *AuthHandler) ConnectSSO(ctx *gin.Context) {
    session := sessions.Default(ctx)
    token := session.Get("access_token")

    if token == nil {
        ctx.JSON(401, gin.H{"error": "No access token"})
        return
    }

    user, err := h.usecase.ConnectSSO(ctx, token.(string))
    if err != nil {
        ctx.JSON(500, gin.H{"error": err.Error()})
        return
    }

    session.Set("user_id", user.ID)
    session.Set("username", user.Username)
    session.Set("logged_in", true)
    session.Save()
    ctx.Redirect(302, "/home")
}

What I’m unsure about:

  • Is it better to create the application session directly in the OAuth callback instead of using a separate /connect endpoint?

  • Is it okay to temporarily store the SSO access token in the session, or should it be avoided?

  • Does having an extra redirect (callback → connect) cause unnecessary complexity or potential issues?

I’m trying to understand the cleanest and most common practice for handling sessions in a web app that relies fully on an internal SSO.