Code Monkey home page Code Monkey logo

workos-go's Introduction

WorkOS Go Library

Go Reference

The WorkOS library for Go provides convenient access to the WorkOS API from applications written in Go.

Documentation

See the API Reference for Go usage examples.

Installation

Install the package with:

go get -u github.com/workos/workos-go/v4...

Configuration

To use the library you must provide an API key, located in the WorkOS dashboard, as an environment variable WORKOS_API_KEY:

WORKOS_API_KEY="sk_1234"

Or, you can set it on your own before your application starts:

sso.Configure(
  "<WORKOS_API_KEY>",
  "<CLIENT_ID>",
  "https://foo-corp.com/redirect-uri"
);

directorysync.SetAPIKey("<WORKOS_API_KEY>");

SDK Versioning

For our SDKs WorkOS follows a Semantic Versioning (SemVer) process where all releases will have a version X.Y.Z (like 1.0.0) pattern wherein Z would be a bug fix (e.g., 1.0.1), Y would be a minor release (1.1.0) and X would be a major release (2.0.0). We permit any breaking changes to only be released in major versions and strongly recommend reading changelogs before making any major version upgrades.

Beta Releases

WorkOS has features in Beta that can be accessed via Beta releases. We would love for you to try these and share feedback with us before these features reach general availability (GA). To install a Beta version, please follow the installation steps above using the Beta release version.

Note: there can be breaking changes between Beta versions. Therefore, we recommend pinning the package version to a specific version. This way you can install the same version each time without breaking changes unless you are intentionally looking for the latest Beta version.

We highly recommend keeping an eye on when the Beta feature you are interested in goes from Beta to stable so that you can move to using the stable version.

More Information

workos-go's People

Contributors

alisherry avatar amadeo-workos avatar ameesha avatar amygdalama avatar ashgodfrey avatar blairlunceford avatar cobbinma avatar danerwilliams avatar dewski avatar drewfradette avatar faroceann avatar frezzle avatar gcarvelli avatar hadihallak avatar jasonroelofs avatar jonatascastro12 avatar jthodge avatar marktran avatar mattgd avatar maxchehab avatar maxdeviant avatar maxence-charriere avatar mthadley avatar oliverzheng avatar rarevalo13 avatar robframpton avatar rohanjadvani avatar sheldonvaughn avatar stanleyphu avatar willmanduffy avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

workos-go's Issues

Failing to marshal JWK returned from `usermanagement.GetJWKSURL`

Using usermanagement.GetJWKSURL, I am given the URL from where I can fetch JWKs to verify a JWT. To do the latter, I am using (or intend to use):

This is a common combination. Below is the recommended approach to setup keyfunk:

usermanagement.SetAPIKey(cfg.WorkOS.APIKey)
jwksUrl, _ := usermanagement.GetJWKSURL(cfg.WorkOS.ClientID)

k, _ := keyfunc.NewDefault([]string{jwksUrl.String()})

// Error handling removed for example brevity

For now, I am expecting my application to start before writing any logic to verify JWTs, however, the last line gives the following error:

 http.go:98: ERROR Failed to refresh HTTP JWK Set from remote HTTP resource. error="failed to create JWK from JWK Marshal: failed to validate JSON Web Key: failed to validate JWK: X5TS256 in marshal does not match X5TS256 in marshalled" url=https://api.workos.com/sso/jwks/<CLIENT_ID>

I'm unfamilliar with JWKs. Is this a problem with the WorkOS implementation of a JWK, or possibly the library I am using? Any insight would be appreciated.

Edit: While I am here, I've also noticed that the decoded JWT does not have the role property in it.

ConnectionType OAuth Function

With the upcoming OAuth migration we need to handle OAuth sso connections differently than non OAuth connections upon login.

Can a a method to ConnectionType be added that tells us whether it is OAuth or not.

func(c ConnectionType) IsOAuthConnection() bool {
   ...
}

Export Public Error Functions

Can you export public error helper functions so i can easily tell what the cause of an error is?

Example of this below; a helper to tell whether an error is a bad request:

func IsErrorBadRequest(err error) bool {
	httpError, ok := err.(workos.HTTPError)
	if !ok {
		return false
	}

	return httpError.Code == http.StatusBadRequest
}

Utility function for getting error code

I notice that there's a function for determining if an error is a 400, but I've encountered errors where the HTTP status code is 422, for example when an email is malformed. It would be great if there were a utility method that could return the status code of a workos HTTPError - right now I'm just looking at the prefix of the error message and seeing if it start with 422.

An alternative is to expose the HTTPError struct so that the client can perform a type assertion.

Support for OIDC Logout URL Generation

OIDC and other SSO integrations support redirecting the user or calling a logout endpoint. Often, an enterprise requirement is to log the user completely out of the application and the identity provider to meet security requirements.

For example, if the user authenticates with OIDC to your application, then logs out of your application. Simply clicking login again, the user will likely not be prompted to sign in to the identity provider again and be automatically logged back in.

To combat this, OIDC implemented RP-Initiated Logout, which allows applications to send the user on logout to the Idp to be completed logged out.

This request is to add GetLogoutURL in the same style as the GetAuthorizationURL API that would build the URL for logging out the user. This method is needed because it requires access to the Well-Known config which is not readily available in the client (it can be done but requires extra code).

Ideally, the SDK would work as follows:

logoutURL, err := client.GetLogoutURL(opts GetLogoutURLOpts{
    RedirectUri: "", // required, where to land after logging out
    State: "", // optional, optional state parameter for the client
    Locale: "", // optional, hint to language of the user
}) 

The API would already know the Client ID and ID Token which are required by OIDC.

Export ValidatePayload

hey guys ๐Ÿ‘‹

apologies if i've got this wrong but should validatePayload be exported in the webhooks package?

func validatePayload(workosHeader string, bodyString string, secret string, defaultTolerance time.Duration) (string, error)

as it stands i can only access the errors.

Configure global metadata

Applications should be able to configure metadata that will be attached to every event published to WorkOS within that process.

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"

	"github.com/dewski/workos/auditlog"
)

func main() {
	auditlog.SetEventMetadata(map[string]interface{}{
		"deployment_sha": os.Getenv("DEPLOYMENT_SHA"),
	})

	http.HandleFunc("/login", func(w http.ResponseWriter, req *http.Request) {
		u := user{
			Email:      "[email protected]",
			DatabaseID: 1,
		}

		event := auditlog.NewEventWithHTTP("user.login", auditlog.Create, req)
		event.SetActor(u)
		event.SetTarget(u)
		err := event.Publish()
		if err != nil {
			// Call out to sentry
			fmt.Println("Had a problem writing this event")
		}

		body, _ := json.Marshal(event)
		fmt.Fprintf(w, string(body))
	})
	log.Fatal(http.ListenAndServe(":8081", nil))
}

LogStreams

It appears that LogStreams is not available in the GoSDK yet. Is this being looked into?

Remove dependency on gjson?

workos-go depends on gjson in internal/workos/http.go. gjson is used there to retrieve a field from a JSON payload, which would be just couple of lines using the stdlib only... Pulling 3rd party deps means everyone using the WorkOS Go SDK pulls them too, which in turn increases the risk of vulnerabilities ending up in our binaries (eg. GHSA-w942-gw6m-p62c - in this case not really a problem if you only parse JSON coming from WorkOS).

Easy fix to remove gjson:

diff --git a/internal/workos/http.go b/internal/workos/http.go
index c4702bc..da03b62 100644
--- a/internal/workos/http.go
+++ b/internal/workos/http.go
@@ -1,11 +1,10 @@
 package workos
 
 import (
+       "encoding/json"
        "fmt"
        "io/ioutil"
        "net/http"
-
-       "github.com/tidwall/gjson"
 )
 
 // TryGetHTTPError returns an error when the http response contains invalid
@@ -20,7 +19,7 @@ func TryGetHTTPError(r *http.Response) error {
        body, err := ioutil.ReadAll(r.Body)
        if err != nil {
                msg = err.Error()
-       } else if m := gjson.GetBytes(body, "message").Str; m != "" {
+       } else if m := getJSONErrorMessage(body); m != "" {
                msg = m
        } else {
                msg = string(body)
@@ -34,6 +33,16 @@ func TryGetHTTPError(r *http.Response) error {
        }
 }
 
+func getJSONErrorMessage(b []byte) string {
+       var response struct{ Message string }
+
+       if err := json.Unmarshal(b, &response); err != nil {
+               return ""
+       }
+
+       return response.Message
+}
+
 // HTTPError represents an http error.
 type HTTPError struct {
        Code      int

Better way to differentiate between 400 errors.

When using GetProfileAndToken, there are a few cases where we might have an error. Namely:

  • The Client ID was invalid.
  • The Secret key was invalid or expired.
  • The code itself was invalid.

We want to handle these cases differently (e.g., have our callback handler return a 500 in the first two cases so alarm bells go off, but a 400 in the latter case since not our problem). However, it's difficult to do this because of the way that the error is returned in the SDK. The JSON bodies of these responses looks like this:

{"error":"invalid_client","error_description":"Invalid client_id."}
{"error":"invalid_client","error_description":"Invalid client secret."}
{"error":"invalid_grant","error_description":"The code 'XXXYYYZZZ' has expired or is invalid."}

...but the workos_error.HTTPError only returns the following:

Code: 400
Status: 400 Bad Request
RequestID: A UUID
ErrorCode: ""
Errors: []
FieldErrors: []
IsRequestError: true
Message (see below)

The message ends up using this logic to mash up the strings, so the three errors I talked about above would result in these Message values:

"invalid_client Invalid client_id"
"invalid_client Invalid client secret."
"invalid_grant The code 'XXXYYYZZZ' has expired or is invalid."

So in the end, while in theory the SDK gives us an error code so that a developer doesn't need to parse a string, I still end up needing to parse a string.

Ideally, the code (e.g., "invalid_client" and "invalid_grant") would be in a field like "ErrorCode.

Why was auto-pagination removed?

Hi,

Right now I'm just trying to figure out how to correctly paginate responses from WorkOS, so I looked in the repo. I saw that auto-pagination was removed in #20. Why was this? Was it faulty in some way? I think I'm probably missing some context.

Expanding metadata automatically

When someone attaches metadata to an event it'd be nice if you could add a struct, for example:

team := Team{
	ID: 1,
	Team: "workos/owners",
}
actor := User{
	ID: 1,
	Email: "[email protected]",
}
user := User{
	ID: 2,
	Email: "[email protected]",
}

event := auditlog.NewEvent("team.add_member", auditlog.Create)
event.SetActor(actor)
event.SetTarget(team)
event.AddMetadata(map[string]interface{}{
	"user": user,
})
{
  "group": "twitter",
  "action": "team.add_member",
  "action_type": "C",
  "actor_name": "[email protected]",
  "actor_id": "user_1",
  "target_name": "workos/owners",
  "target_id": "team_1",
  "location": "1.1.1.1",
  "occured_at": "2019-05-01T01:15:55.619355Z",
  "metadata": {
    "user_name": "[email protected]",
    "user_id": "user_2"
  }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.