code: func (h *Handler) createSession(w http.ResponseWriter, r *http.Request, p httprouter.Params) (interface{}, error) {
  	var req *createSessionReq
  	if err := httplib.ReadJSON(r, &req); err != nil {
  		return nil, trace.Wrap(err)
  	}
  
  	// get cluster preferences to see if we should login
  	// with password or password+otp
  	authClient := h.cfg.ProxyClient
  	cap, err := authClient.GetAuthPreference()
  	if err != nil {
  		return nil, trace.Wrap(err)
  	}
  
  	var webSession services.WebSession
  
  	switch cap.GetSecondFactor() {
  	case teleport.OFF:
  		webSession, err = h.auth.AuthWithoutOTP(req.User, req.Pass)
  	case teleport.OTP, teleport.HOTP, teleport.TOTP:
  		webSession, err = h.auth.AuthWithOTP(req.User, req.Pass, req.SecondFactorToken)
  	default:
  		return nil, trace.AccessDenied("unknown second factor type: %q", cap.GetSecondFactor())
  	}
  	if err != nil {
  		return nil, trace.AccessDenied("bad auth credentials")
  	}
  
  	if err := SetSession(w, req.User, webSession.GetName()); err != nil {
  		return nil, trace.Wrap(err)
  	}
  
  	ctx, err := h.auth.ValidateSession(req.User, webSession.GetName())
  	if err != nil {
  		return nil, trace.AccessDenied("need auth")
  	}
  
  	return NewSessionResponse(ctx)
  }
docs: // createSession creates a new web session based on user, pass and 2nd factor token
  //
  // POST /v1/webapi/sessions
  //
  // {"user": "alex", "pass": "abc123", "second_factor_token": "token", "second_factor_type": "totp"}
  //
  // Response
  //
  // {"type": "bearer", "token": "bearer token", "user": {"name": "alex", "allowed_logins": ["admin", "bob"]}, "expires_in": 20}
  //