Session returns the AuthResponse bound to the caller's cookie/bearer and rotates the session token in the process. Transport-agnostic port of graphqlProvider.Session. Security note: SessionResponse carries access_token, refresh_token, id_token, and authenticator-enrolment fields. Per security audit
(ctx context.Context, meta RequestMetadata, params *model.SessionQueryRequest)
| 25 | // proto annotation on Session is `mcp_tool.exposed = false` — so this |
| 26 | // response shape never lands in an MCP/LLM transcript. |
| 27 | func (p *provider) Session(ctx context.Context, meta RequestMetadata, params *model.SessionQueryRequest) (*model.AuthResponse, *ResponseSideEffects, error) { |
| 28 | log := p.Log.With().Str("func", "Session").Logger() |
| 29 | side := &ResponseSideEffects{} |
| 30 | |
| 31 | gc := &gin.Context{Request: meta.Request} |
| 32 | sessionToken, err := cookie.GetSession(gc) |
| 33 | if err != nil { |
| 34 | log.Debug().Err(err).Msg("Failed to get session token") |
| 35 | return nil, nil, Unauthenticated("unauthorized") |
| 36 | } |
| 37 | |
| 38 | claims, err := p.TokenProvider.ValidateBrowserSession(gc, sessionToken) |
| 39 | if err != nil { |
| 40 | log.Debug().Err(err).Msg("Failed to validate session token") |
| 41 | return nil, nil, Unauthenticated("unauthorized") |
| 42 | } |
| 43 | userID := claims.Subject |
| 44 | log = log.With().Str("user_id", userID).Logger() |
| 45 | user, err := p.StorageProvider.GetUserByID(ctx, userID) |
| 46 | if err != nil { |
| 47 | log.Debug().Err(err).Msg("Failed to get user") |
| 48 | return nil, nil, err |
| 49 | } |
| 50 | |
| 51 | claimRoles := append([]string{}, claims.Roles...) |
| 52 | if params != nil && len(params.Roles) > 0 { |
| 53 | for _, v := range params.Roles { |
| 54 | if !utils.StringSliceContains(claimRoles, v) { |
| 55 | log.Debug().Msg("User does not have required role") |
| 56 | return nil, nil, Unauthenticated("unauthorized") |
| 57 | } |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | // Fine-grained authorization gate (AND semantics, fail-closed). |
| 62 | if params != nil && len(params.RequiredRelations) > 0 { |
| 63 | if err := p.enforceRequiredRelations(ctx, log, userID, params.RequiredRelations); err != nil { |
| 64 | log.Debug().Err(err).Msg("Required relations not satisfied") |
| 65 | return nil, nil, err |
| 66 | } |
| 67 | } |
| 68 | |
| 69 | scope := []string{"openid", "email", "profile"} |
| 70 | if params != nil && len(params.Scope) > 0 { |
| 71 | scope = params.Scope |
| 72 | } |
| 73 | |
| 74 | // OIDC authorize flow: if state is provided, consume the authorize state |
| 75 | // and prepare code/challenge data so the authorization code can be stored |
| 76 | // after token creation. |
| 77 | code := "" |
| 78 | codeChallenge := "" |
| 79 | oidcNonce := "" |
| 80 | authorizeRedirectURI := "" |
| 81 | if params != nil && params.State != nil { |
| 82 | authorizeState, _ := p.MemoryStoreProvider.GetState(refs.StringValue(params.State)) |
| 83 | if authorizeState != "" { |
| 84 | parts := strings.Split(authorizeState, "@@") |
nothing calls this directly
no test coverage detected