Here’s an implementation of InSessionScope(). I fall back to Singleton scoping when session isn’t available (mainly to make testing easier):

using System.Web;
using Ninject.Activation;
using Ninject.Syntax;

public static class SessionScopeExtensions
{
    private const string _sessionKey = "Ninject Session Scope Sync Root";
    private static readonly object singleton = new object();

    public static IBindingNamedWithOrOnSyntax<T> InSessionScope<T>(this IBindingInSyntax<T> parent)
    {
        return parent.InScope(SessionScopeCallback);
    }

    private static object SessionScopeCallback(IContext context)
    {
        if (HttpContext.Current == null || HttpContext.Current.Session == null)
            return singleton;

        if (HttpContext.Current.Session[_sessionKey] == null)
        {
            HttpContext.Current.Session[_sessionKey] = new object();
        }

        return HttpContext.Current.Session[_sessionKey];
    }
}

If we need to synchronize session between MVC and Web API, we need to add the following to the Global.asax:

protected void Application_PostAuthorizeRequest()
{
    HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required);
}