{"id":714,"date":"2024-11-26T12:30:03","date_gmt":"2024-11-26T20:30:03","guid":{"rendered":"https:\/\/embedded.gusto.com\/blog\/?p=714"},"modified":"2024-11-26T12:30:03","modified_gmt":"2024-11-26T20:30:03","slug":"partner-requests-roadmap","status":"publish","type":"post","link":"https:\/\/embedded.gusto.com\/blog\/partner-requests-roadmap\/","title":{"rendered":"How We Solve for Partner-Specific Requests"},"content":{"rendered":"<p><span style=\"font-weight: 400;\">We\u2019re building Gusto Embedded as a <a href=\"https:\/\/docs.gusto.com\/embedded-payroll\/docs\/introduction\">set of APIs and prebuilt components<\/a> to be customized by our partners, so they can deliver the best payroll experience for their customers. But not everything is one-size-fits all: sometimes our partners need <\/span><i><span style=\"font-weight: 400;\">us<\/span><\/i><span style=\"font-weight: 400;\"> to customize the product experience to meet their needs.\u00a0<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">Every partner is different, and requirements vary. Generally, we aim to prioritize the projects on our roadmap that will have the greatest impact for the largest number of partners and employers.\u00a0<\/span><\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"font-weight: 400;\">First, we start by understanding our partners\u2019 needs. One partner, for example, requested that we limit the Gusto-hosted interfaces an employer or employee can access, restricting them from logging into Gusto.com. This helps our partner strengthen their brand as a payroll leader and reduces potential confusion for their customers.\u00a0<\/span><\/p>\n<h3><b>Understanding the Challenge<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">This seemed like a straightforward enough request, but with it came a lot of nuances that we had to explore in depth. And while the request came initially from one partner, we acknowledged the benefits this feature could have for all partners that choose to enable it \u2013 and, indeed, had heard from other partners that this was also on their roadmaps. It was time to start scoping.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Here&#8217;s where things got tricky: our existing infrastructure didn\u2019t account for embedded partner access at the login level. We had to figure out a way to determine which partner and which user roles should be blocked from accessing certain resources at both the login level and the in-app level.\u00a0<\/span><\/p>\n<h3><b>Identifying the Problems<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">Before diving into solutions, we had to understand the core problems:<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Role-Based Blocking<\/b><span style=\"font-weight: 400;\">: Partners wanted to restrict access for certain roles. For instance, employees and payroll admins should be blocked from accessing some Gusto resources, but contractors and accountants should still be able to access them. This required a role-specific control mechanism.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Multi-Role Complexity<\/b><span style=\"font-weight: 400;\">: In our system, a user might hold multiple roles across different companies under one user account. For example, someone could be an employee at one company and a contractor at another. There could be a mix and match of blocked companies, partners, and user roles per user we had to consider.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Account Switching<\/b><span style=\"font-weight: 400;\">:\u00a0 In our Gusto app, we allow a user to switch between their user role accounts, so even if a user\u2019s role was blocked, they might still have access via a different role. In such cases, we had to allow the user to login, but prevent them from switching to the restricted account. We worked a lot with our Security teams and GraphQL teams to make sure our changes were valid.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Third-party Logins: <\/b><span style=\"font-weight: 400;\">There are many ways to login to Gusto besides the traditional email\/password login, including Google OAuth, Intuit login, etc. that we had to consider when blocking a user login.<\/span><\/li>\n<\/ol>\n<p><img decoding=\"async\" class=\"alignnone size-full wp-image-716 lazyload\" data-src=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/11\/emb-blog-diagram-providingforpartners.png\" alt=\"embedded login diagram\" width=\"1381\" height=\"622\" data-srcset=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/11\/emb-blog-diagram-providingforpartners.png 1381w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/11\/emb-blog-diagram-providingforpartners-425x191.png 425w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/11\/emb-blog-diagram-providingforpartners-1200x540.png 1200w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/11\/emb-blog-diagram-providingforpartners-150x68.png 150w, https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/11\/emb-blog-diagram-providingforpartners-768x346.png 768w\" data-sizes=\"(max-width: 1381px) 100vw, 1381px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1381px; --smush-placeholder-aspect-ratio: 1381\/622;\" \/><\/p>\n<p><i><span style=\"font-weight: 400;\">Simplified workflow of determining whether a user should be blocked when logging into Gusto<\/span><\/i><\/p>\n<h3><b>Building the Solution<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">About a year ago, when we planned this project, we decided to roll it out in phases to better meet customer needs. In the first phase, we focused on partners with net-new embedded customers\u2014those who hadn&#8217;t used Gusto before\u2014because they made up the bulk of our customer base. This approach let us get an MVP out the door quickly and start testing things right away. In the second phase, we tackled more complex cases, like partners with embedded companies that used to be Gusto customers. By breaking it up like this, we could deliver faster and fine-tune as we went along.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">To address these challenges we started by working on these steps:<\/span><\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Configuring Partner Settings<\/b><span style=\"font-weight: 400;\">: Through this new configuration only available internally, our CX (customer experience) team members could enable or disable this feature for partners. This flexibility allowed partners to choose whether to use Gusto directly for certain features or keep their customers within their own app.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Adding a new Blocked Company Model<\/b><span style=\"font-weight: 400;\">: We introduced a new model to manage partner-specific login controls. This model enabled us to configure whether a company under an embedded partner had blocking enabled, and is maintained by Sidekiq jobs that would run whenever the partner was modified.\u00a0<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Role-Specific Blocking Logic<\/b><span style=\"font-weight: 400;\">: We keep a list of roles that are explicitly blocked, and we use this to decide whether a user&#8217;s role should prevent them from accessing certain resources on Gusto. For instance, if the employee role is restricted, the system will block them from logging in, but still allow access if they&#8217;re logged in as a contractor. We also had to build in extra logic to handle situations where an employee had been a Gusto customer in the past, ensuring their account was managed properly.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Handling Account Switching<\/b><span style=\"font-weight: 400;\">: When a user with multiple roles logged in, we ensured they could still access non-restricted accounts. However, if one of their roles was blocked, they couldn\u2019t switch to that account once logged in. We needed to ensure that the default login did not automatically select a blocked company.<\/span><\/li>\n<li><b>Handling Login blocking<\/b><span style=\"font-weight: 400;\">: We added the block check at the main login entry point and third party login entry points, making sure to raise a generic login error due to security guidance.<\/span><\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<h3><\/h3>\n<h3><b>Performance and Security<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">For this project, since we were working with logins\u2014the most frequently accessed part of Gusto\u2014it was crucial to keep everything fast and secure. Gusto developed a slow query checker that engineers could use to debug performance issues. This tool was especially useful when adding block checks across various key parts of the codebase, ensuring everything performed as smoothly as possible.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">On the security side, we had to be careful not to introduce any vulnerabilities with this project. Following advice from our Security team, we avoided showing a specific &#8220;blocked&#8221; error message. Instead, if a user was blocked, we\u2019d show a generic error message that didn\u2019t unintentionally reveal any details about the partner or end customer.<\/span><\/p>\n<h3><b>Conclusion<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">This access project was a complex, multi-faceted solution to a problem that impacted both Gusto and our partners. We collaborated with a multitude of teams across Gusto, including Identity, Security, PeopleOS, and the GraphQL teams. By focusing on flexibility and control, we enabled partners to create the experience they wanted for their customers, while still leveraging Gusto\u2019s powerful backend capabilities. This experience reinforced the importance of clear documentation, early planning, and a deep understanding of customer needs.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">For our partners, this new feature unlocks a new level of customization. It allows them to decide when they\u2019d like to lean on existing Gusto functionality, and when they\u2019d like to build out more nuanced features themselves \u2013 a major benefit of working with a company like Gusto that\u2019s been building and handling payroll for over 12 years. <\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>We\u2019re building Gusto Embedded as a set of APIs and prebuilt components to be customized by our partners, so they&#8230;<\/p>\n","protected":false},"author":23,"featured_media":715,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[4],"tags":[],"class_list":["post-714","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-developer-perspective"],"acf":{"exclude_from_embedded_resources":false,"popularity":0,"essentiality":0},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>How We Solve for Partner-Specific Requests - Embedded Blog<\/title>\n<meta name=\"description\" content=\"A deep dive into how the Gusto Embedded team handles partner-specific feature requests, and how we prioritize our roadmap.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/embedded.gusto.com\/blog\/partner-requests-roadmap\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How We Solve for Partner-Specific Requests - Embedded Blog\" \/>\n<meta property=\"og:description\" content=\"A deep dive into how the Gusto Embedded team handles partner-specific feature requests, and how we prioritize our roadmap.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/embedded.gusto.com\/blog\/partner-requests-roadmap\/\" \/>\n<meta property=\"og:site_name\" content=\"Embedded Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-11-26T20:30:03+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/11\/EMB-blog-hero-partnerrequests.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1920\" \/>\n\t<meta property=\"og:image:height\" content=\"1080\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Shirley Liu\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Shirley Liu\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutes\" \/>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How We Solve for Partner-Specific Requests - Embedded Blog","description":"A deep dive into how the Gusto Embedded team handles partner-specific feature requests, and how we prioritize our roadmap.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/embedded.gusto.com\/blog\/partner-requests-roadmap\/","og_locale":"en_US","og_type":"article","og_title":"How We Solve for Partner-Specific Requests - Embedded Blog","og_description":"A deep dive into how the Gusto Embedded team handles partner-specific feature requests, and how we prioritize our roadmap.","og_url":"https:\/\/embedded.gusto.com\/blog\/partner-requests-roadmap\/","og_site_name":"Embedded Blog","article_published_time":"2024-11-26T20:30:03+00:00","og_image":[{"width":1920,"height":1080,"url":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/11\/EMB-blog-hero-partnerrequests.png","type":"image\/png"}],"author":"Shirley Liu","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Shirley Liu","Est. reading time":"6 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/embedded.gusto.com\/blog\/partner-requests-roadmap\/#article","isPartOf":{"@id":"https:\/\/embedded.gusto.com\/blog\/partner-requests-roadmap\/"},"author":{"name":"Shirley Liu","@id":"https:\/\/embedded.gusto.com\/blog\/#\/schema\/person\/d5276df626da35f6fffdf2b0fbec1fb7"},"headline":"How We Solve for Partner-Specific Requests","datePublished":"2024-11-26T20:30:03+00:00","mainEntityOfPage":{"@id":"https:\/\/embedded.gusto.com\/blog\/partner-requests-roadmap\/"},"wordCount":1130,"image":{"@id":"https:\/\/embedded.gusto.com\/blog\/partner-requests-roadmap\/#primaryimage"},"thumbnailUrl":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/11\/EMB-blog-hero-partnerrequests.png","articleSection":["Developer Perspective"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/embedded.gusto.com\/blog\/partner-requests-roadmap\/","url":"https:\/\/embedded.gusto.com\/blog\/partner-requests-roadmap\/","name":"How We Solve for Partner-Specific Requests - Embedded Blog","isPartOf":{"@id":"https:\/\/embedded.gusto.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/embedded.gusto.com\/blog\/partner-requests-roadmap\/#primaryimage"},"image":{"@id":"https:\/\/embedded.gusto.com\/blog\/partner-requests-roadmap\/#primaryimage"},"thumbnailUrl":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/11\/EMB-blog-hero-partnerrequests.png","datePublished":"2024-11-26T20:30:03+00:00","author":{"@id":"https:\/\/embedded.gusto.com\/blog\/#\/schema\/person\/d5276df626da35f6fffdf2b0fbec1fb7"},"description":"A deep dive into how the Gusto Embedded team handles partner-specific feature requests, and how we prioritize our roadmap.","breadcrumb":{"@id":"https:\/\/embedded.gusto.com\/blog\/partner-requests-roadmap\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/embedded.gusto.com\/blog\/partner-requests-roadmap\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/embedded.gusto.com\/blog\/partner-requests-roadmap\/#primaryimage","url":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/11\/EMB-blog-hero-partnerrequests.png","contentUrl":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/11\/EMB-blog-hero-partnerrequests.png","width":1920,"height":1080,"caption":"solving for partner specific requests"},{"@type":"BreadcrumbList","@id":"https:\/\/embedded.gusto.com\/blog\/partner-requests-roadmap\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/embedded.gusto.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How We Solve for Partner-Specific Requests"}]},{"@type":"WebSite","@id":"https:\/\/embedded.gusto.com\/blog\/#website","url":"https:\/\/embedded.gusto.com\/blog\/","name":"Embedded Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/embedded.gusto.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/embedded.gusto.com\/blog\/#\/schema\/person\/d5276df626da35f6fffdf2b0fbec1fb7","name":"Shirley Liu","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/11\/shirley-liu-150x150.jpeg","url":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/11\/shirley-liu-150x150.jpeg","contentUrl":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/11\/shirley-liu-150x150.jpeg","caption":"Shirley Liu"},"description":"Shirley Liu is a software engineer on the Gusto Embedded Payroll team focusing on building out APIs and solutions for our partners. Previously, she was on the benefits team automating health insurance flows with our carriers. Shirley graduated from UC Berkeley with a degree in Electrical Engineering and Computer Science. Shirley is from the LA area and plays volleyball with Gusto!","url":"https:\/\/embedded.gusto.com\/blog\/author\/shirley-liu\/"}]}},"images":{"large":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/11\/EMB-blog-hero-partnerrequests-1120x630.png"},"authorDetails":{"id":23,"name":"Shirley Liu","avatar":"https:\/\/embeddedblog.wpengine.com\/wp-content\/uploads\/2024\/11\/shirley-liu-150x150.jpeg"},"_links":{"self":[{"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/posts\/714","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/users\/23"}],"replies":[{"embeddable":true,"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/comments?post=714"}],"version-history":[{"count":0,"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/posts\/714\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/media\/715"}],"wp:attachment":[{"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/media?parent=714"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/categories?post=714"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/embedded.gusto.com\/blog\/wp-json\/wp\/v2\/tags?post=714"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}