Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add B2B endpoints #115

Merged
merged 12 commits into from
May 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ linters-settings:
goimports:
local-prefixes: github.com/stytchauth/stytch-go/stytch
lll:
line-length: 100
line-length: 150
issues:
exclude-rules:
# Ignore comments with long urls
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ It pairs well with the Stytch [Web SDK](https://www.npmjs.com/package/@stytch/st
## Install

```console
$ go get github.com/stytchauth/stytch-go/v7
$ go get github.com/stytchauth/stytch-go/v8
```

## Usage
Expand All @@ -34,8 +34,8 @@ Create an API client:
import (
"os"

"github.com/stytchauth/stytch-go/v7/stytch"
"github.com/stytchauth/stytch-go/v7/stytch/stytchapi"
"github.com/stytchauth/stytch-go/v8/stytch"
"github.com/stytchauth/stytch-go/v8/stytch/stytchapi"
)

stytchAPIClient, err := stytchapi.NewAPIClient(
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module github.com/stytchauth/stytch-go/v7
module github.com/stytchauth/stytch-go/v8

go 1.18

Expand Down
70 changes: 70 additions & 0 deletions stytch/b2b/b2bstytchapi/b2bstytchapi.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package b2bstytchapi

import (
"github.com/stytchauth/stytch-go/v8/stytch"
"github.com/stytchauth/stytch-go/v8/stytch/b2b/discovery"
"github.com/stytchauth/stytch-go/v8/stytch/b2b/magiclink"
mle "github.com/stytchauth/stytch-go/v8/stytch/b2b/magiclink/email"
"github.com/stytchauth/stytch-go/v8/stytch/b2b/organization"
"github.com/stytchauth/stytch-go/v8/stytch/b2b/password"
pe "github.com/stytchauth/stytch-go/v8/stytch/b2b/password/email"
pep "github.com/stytchauth/stytch-go/v8/stytch/b2b/password/existingpassword"
ps "github.com/stytchauth/stytch-go/v8/stytch/b2b/password/session"
"github.com/stytchauth/stytch-go/v8/stytch/b2b/session"
"github.com/stytchauth/stytch-go/v8/stytch/b2b/sso"
"github.com/stytchauth/stytch-go/v8/stytch/b2b/sso/oidc"
"github.com/stytchauth/stytch-go/v8/stytch/b2b/sso/saml"
"github.com/stytchauth/stytch-go/v8/stytch/config"
)

type Logger interface {
Printf(format string, v ...interface{})
}

type API struct {
client *stytch.Client
logger Logger
MagicLinks *magiclink.Client
Organization *organization.Client
Session *session.Client
Passwords *password.Client
Discovery *discovery.Client
SSO *sso.Client
}

type Option func(*API)

func WithLogger(logger Logger) Option {
return func(api *API) { api.logger = logger }
}

// WithBaseURI overrides the client base URI determined by the environment.
//
// The value derived from stytch.EnvLive or stytch.EnvTest is already correct for production use
// in the Live or Test environment, respectively. This is implemented to make it easier to use
// this client to access internal development versions of the API.
func WithBaseURI(uri string) Option {
return func(api *API) { api.client.Config.BaseURI = config.BaseURI(uri) }
}

func NewAPIClient(env config.Env, projectID string, secret string, opts ...Option) (*API, error) {
a := &API{
client: stytch.New(env, projectID, secret),
}
for _, o := range opts {
o(a)
}

a.MagicLinks = &magiclink.Client{C: a.client, Email: &mle.Client{C: a.client}}
a.Organization = &organization.Client{C: a.client}
a.Session = &session.Client{C: a.client}
a.Passwords = &password.Client{
C: a.client,
Email: &pe.Client{C: a.client},
Session: &ps.Client{C: a.client},
ExistingPassword: &pep.Client{C: a.client},
}
a.Discovery = &discovery.Client{C: a.client}
a.SSO = &sso.Client{C: a.client, OIDC: &oidc.Client{C: a.client}, SAML: &saml.Client{C: a.client}}
return a, nil
}
71 changes: 71 additions & 0 deletions stytch/b2b/discovery.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package b2b

type DiscoveryListOrganizationsParams struct {
IntermediateSessionToken string `json:"intermediate_session_token,omitempty"`
SessionToken string `json:"session_token,omitempty"`
SessionJwt string `json:"session_jwt,omitempty"`
}

type DiscoveryListOrganizationsResponse struct {
RequestID string `json:"request_id,omitempty"`
StatusCode int `json:"status_code,omitempty"`
EmailAddress string `json:"email_address,omitempty"`
DiscoveredOrganizations []DiscoveredOrganization `json:"discovered_organizations,omitempty"`
}

type DiscoveryIntermediateSessionExchangeParams struct {
IntermediateSessionToken string `json:"intermediate_session_token"`
OrganizationID string `json:"organization_id"`
SessionDurationMinutes int32 `json:"session_duration_minutes,omitempty"`
SessionCustomClaims map[string]any `json:"session_custom_claims,omitempty"`
}

type DiscoveryIntermediateSessionExchangeResponse struct {
RequestID string `json:"request_id,omitempty"`
StatusCode int `json:"status_code,omitempty"`
MemberID string `json:"member_id,omitempty"`
MemberSession MemberSession `json:"member_session,omitempty"`
SessionToken string `json:"session_token,omitempty"`
SessionJWT string `json:"session_jwt,omitempty"`
Member Member `json:"member,omitempty"`
Organization Organization `json:"organization,omitempty"`
}

type DiscoveryOrganizationCreateParams struct {
IntermediateSessionToken string `json:"intermediate_session_token"`
SessionDurationMinutes int32 `json:"session_duration_minutes,omitempty"`
SessionCustomClaims map[string]any `json:"session_custom_claims,omitempty"`
OrganizationName string `json:"organization_name,omitempty"`
OrganizationSlug string `json:"organization_slug,omitempty"`
OrganizationLogoURL string `json:"organization_logo_url,omitempty"`
TrustedMetadata map[string]any `json:"trusted_metadata,omitempty"`
SsoJitProvisioning string `json:"sso_jit_provisioning,omitempty"`
EmailAllowedDomains []string `json:"email_allowed_domains,omitempty"`
EmailJitProvisioning string `json:"email_jit_provisioning,omitempty"`
EmailInvites string `json:"email_invites,omitempty"`
AuthMethods string `json:"auth_methods,omitempty"`
AllowedAuthMethods []string `json:"allowed_auth_methods,omitempty"`
}

type DiscoveryOrganizationCreateResponse struct {
RequestID string `json:"request_id,omitempty"`
StatusCode int `json:"status_code,omitempty"`
MemberID string `json:"member_id,omitempty"`
MemberSession MemberSession `json:"member_session,omitempty"`
SessionToken string `json:"session_token,omitempty"`
SessionJWT string `json:"session_jwt,omitempty"`
Member Member `json:"member,omitempty"`
Organization Organization `json:"organization,omitempty"`
}

type DiscoveredOrganization struct {
Organization Organization `json:"organization,omitempty"`
Membership Membership `json:"membership,omitempty"`
MemberAuthenticated bool `json:"member_authenticated,omitempty"`
}

type Membership struct {
Type string `json:"type,omitempty"`
Details map[string]interface{} `json:"details,omitempty"`
Member Member `json:"member,omitempty"`
}
80 changes: 80 additions & 0 deletions stytch/b2b/discovery/discovery.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package discovery

import (
"context"
"encoding/json"

"github.com/stytchauth/stytch-go/v8/stytch"
"github.com/stytchauth/stytch-go/v8/stytch/b2b"
"github.com/stytchauth/stytch-go/v8/stytch/stytcherror"
)

type Client struct {
C *stytch.Client
}

func (c *Client) List(
ctx context.Context,
body *b2b.DiscoveryListOrganizationsParams,
) (*b2b.DiscoveryListOrganizationsResponse, error) {
path := "/b2b/discovery/organizations"

var jsonBody []byte
var err error
if body != nil {
jsonBody, err = json.Marshal(body)
if err != nil {
return nil, stytcherror.NewClientLibraryError(
"Oops, something seems to have gone wrong " +
"marshalling the /b2b/discovery/organizations request body")
}
}

var retVal b2b.DiscoveryListOrganizationsResponse
err = c.C.NewRequest(ctx, "POST", path, nil, jsonBody, &retVal)
return &retVal, err
}

func (c *Client) IntermediateSessionExchange(
ctx context.Context,
body *b2b.DiscoveryIntermediateSessionExchangeParams,
) (*b2b.DiscoveryIntermediateSessionExchangeResponse, error) {
path := "/b2b/discovery/intermediate_sessions/exchange"

var jsonBody []byte
var err error
if body != nil {
jsonBody, err = json.Marshal(body)
if err != nil {
return nil, stytcherror.NewClientLibraryError(
"Oops, something seems to have gone wrong " +
"marshalling the /b2b/discovery/intermediate_sessions/exchange request body")
}
}

var retVal b2b.DiscoveryIntermediateSessionExchangeResponse
err = c.C.NewRequest(ctx, "POST", path, nil, jsonBody, &retVal)
return &retVal, err
}

func (c *Client) OrganizationCreate(
ctx context.Context,
body *b2b.DiscoveryOrganizationCreateParams,
) (*b2b.DiscoveryOrganizationCreateResponse, error) {
path := "/b2b/discovery/organizations/create"

var jsonBody []byte
var err error
if body != nil {
jsonBody, err = json.Marshal(body)
if err != nil {
return nil, stytcherror.NewClientLibraryError(
"Oops, something seems to have gone wrong " +
"marshalling the /b2b/discovery/organizations/create request body")
}
}

var retVal b2b.DiscoveryOrganizationCreateResponse
err = c.C.NewRequest(ctx, "POST", path, nil, jsonBody, &retVal)
return &retVal, err
}
91 changes: 91 additions & 0 deletions stytch/b2b/magiclink.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package b2b

type MagicLinksAuthenticateParams struct {
MagicLinksToken string `json:"magic_links_token"`
SessionToken string `json:"session_token,omitempty"`
SessionJWT string `json:"session_jwt,omitempty"`
SessionDurationMinutes int32 `json:"session_duration_minutes,omitempty"`
SessionCustomClaims map[string]interface{} `json:"session_custom_claims,omitempty"`
PKCECodeVerifier string `json:"pkce_code_verifier,omitempty"`
}

type MagicLinksAuthenticateResponse struct {
RequestID string `json:"request_id,omitempty"`
StatusCode int `json:"status_code,omitempty"`
MemberID string `json:"member_id,omitempty"`
MethodID string `json:"method_id,omitempty"`
ResetSessions bool `json:"reset_sessions,omitempty"`
OrganizationID string `json:"organization_id,omitempty"`
Member Member `json:"member,omitempty"`
SessionToken string `json:"session_token,omitempty"`
SessionJWT string `json:"session_jwt,omitempty"`
MemberSession MemberSession `json:"member_session,omitempty"`
Organization Organization `json:"organization,omitempty"`
}

type MagicLinksDiscoveryAuthenticateParams struct {
DiscoveryMagicLinksToken string `json:"discovery_magic_links_token"`
PKCECodeVerifier string `json:"pkce_code_verifier,omitempty"`
}

type MagicLinksDiscoveryAuthenticateResponse struct {
RequestID string `json:"request_id,omitempty"`
StatusCode int `json:"status_code,omitempty"`
IntermediateSessionToken string `json:"intermediate_session_token,omitempty"`
EmailAddress string `json:"email_address,omitempty"`
DiscoveredOrganizations []DiscoveredOrganization `json:"discovered_organizations,omitempty"`
}

// MAGIC LINK - EMAIL
type MagicLinksEmailLoginOrSignupParams struct {
OrganizationID string `json:"organization_id"`
EmailAddress string `json:"email_address"`
LoginMagicLinkURL string `json:"login_magic_link_url,omitempty"`
SignupMagicLinkURL string `json:"signup_magic_link_url,omitempty"`
LoginExpirationMinutes int32 `json:"login_expiration_minutes,omitempty"`
PKCECodeChallenge string `json:"pkce_code_challenge,omitempty"`
LoginTemplateID string `json:"login_template_id,omitempty"`
SignupTemplateID string `json:"signup_template_id,omitempty"`
Locale string `json:"locale,omitempty"`
}

type MagicLinksEmailLoginOrSignupResponse struct {
RequestID string `json:"request_id,omitempty"`
StatusCode int `json:"status_code,omitempty"`
MemberID string `json:"member_id,omitempty"`
MemberCreated bool `json:"member_created,omitempty"`
Member Member `json:"member,omitempty"`
Organization Organization `json:"organization,omitempty"`
}

type MagicLinksEmailInviteParams struct {
OrganizationID string `json:"organization_id"`
EmailAddress string `json:"email_address"`
InviteRedirectURL string `json:"invite_redirect_url,omitempty"`
InvitedByMemberID string `json:"invited_by_member_id,omitempty"`
Name string `json:"name,omitempty"`
TrustedMetadata map[string]any `json:"trusted_metadata,omitempty"`
UntrustedMetadata map[string]any `json:"untrusted_metadata,omitempty"`
InviteTemplateID string `json:"invite_template_id,omitempty"`
Locale string `json:"locale,omitempty"`
}
type MagicLinksEmailInviteResponse struct {
RequestID string `json:"request_id,omitempty"`
StatusCode int `json:"status_code,omitempty"`
MemberID string `json:"member_id,omitempty"`
Member Member `json:"member,omitempty"`
Organization Organization `json:"organization,omitempty"`
}

type MagicLinksEmailDiscoverySendParams struct {
EmailAddress string `json:"email_address"`
DiscoveryRedirectURL string `json:"discovery_redirect_url,omitempty"`
PkceCodeChallenge string `json:"pkce_code_challenge,omitempty"`
LoginTemplateID string `json:"login_template_id,omitempty"`
Locale string `json:"locale,omitempty"`
}

type MagicLinksEmailDiscoverySendResponse struct {
RequestID string `json:"request_id,omitempty"`
StatusCode int `json:"status_code,omitempty"`
}
Loading