diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6565fb7..840bd90 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -2,23 +2,19 @@ name: tests
on:
push:
- branches:
- - 'main'
- pull_request:
- branches:
- - 'main'
+ branches: '*'
concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
jobs:
- unit-test:
- uses: "./.github/workflows/ci_unit_test.yml"
+ unittests:
+ uses: "./.github/workflows/ci_unittests.yml"
secrets: inherit
- integration-test:
- uses: "./.github/workflows/ci_integration_test.yml"
+ integrationtests:
+ uses: "./.github/workflows/ci_integrationtests.yml"
secrets: inherit
lint:
diff --git a/.github/workflows/ci_integration_test.yml b/.github/workflows/ci_integrationtests.yml
similarity index 69%
rename from .github/workflows/ci_integration_test.yml
rename to .github/workflows/ci_integrationtests.yml
index 1921a91..f940f1d 100644
--- a/.github/workflows/ci_integration_test.yml
+++ b/.github/workflows/ci_integrationtests.yml
@@ -1,10 +1,10 @@
-name: integration-test
+name: integrationtests
on:
workflow_call:
jobs:
- test:
+ integrationtests:
runs-on: ubuntu-latest
strategy:
@@ -12,6 +12,9 @@ jobs:
matrix:
go:
- '1.18'
+ - '1.19'
+ - '1.20'
+ - '1.21'
steps:
- uses: actions/checkout@v3
@@ -21,8 +24,9 @@ jobs:
go-version: ${{ matrix.go }}
cache: true
- - env:
+ - name: Run integration tests
+ env:
CORBADO_BACKEND_API: ${{ secrets.CORBADO_BACKEND_API }}
CORBADO_PROJECT_ID: ${{ secrets.CORBADO_PROJECT_ID }}
CORBADO_API_SECRET: ${{ secrets.CORBADO_API_SECRET }}
- run: go test -tags=integration ./tests/integration/...
\ No newline at end of file
+ run: go test -tags=integration ./tests/integration/...
diff --git a/.github/workflows/ci_unit_test.yml b/.github/workflows/ci_unittests.yml
similarity index 65%
rename from .github/workflows/ci_unit_test.yml
rename to .github/workflows/ci_unittests.yml
index 161d8a4..6149583 100644
--- a/.github/workflows/ci_unit_test.yml
+++ b/.github/workflows/ci_unittests.yml
@@ -1,10 +1,10 @@
-name: unit-test
+name: unittests
on:
workflow_call:
jobs:
- test:
+ unittests:
runs-on: ubuntu-latest
strategy:
@@ -12,6 +12,9 @@ jobs:
matrix:
go:
- '1.18'
+ - '1.19'
+ - '1.20'
+ - '1.21'
steps:
- uses: actions/checkout@v3
@@ -20,5 +23,6 @@ jobs:
with:
go-version: ${{ matrix.go }}
cache: true
-
- - run: go test ./...
\ No newline at end of file
+
+ - name: Run unit tests
+ run: go test ./...
diff --git a/README.md b/README.md
index 4d3c554..9c204ab 100644
--- a/README.md
+++ b/README.md
@@ -1,44 +1,156 @@
-# Corbado Go SDK
+
-Go SDK for Corbado Backend API
+# Corbado Go SDK
[![Go Reference](https://pkg.go.dev/badge/github.com/corbado/corbado-go.svg)](https://pkg.go.dev/github.com/corbado/corbado-go)
+[![License](https://poser.pugx.org/corbado/php-sdk/license.svg)](https://packagist.org/packages/corbado/php-sdk)
[![Test Status](https://github.com/corbado/corbado-go/workflows/tests/badge.svg)](https://github.com/corbado/corbado-go/actions?query=workflow%3Atests)
-[![documentation](https://img.shields.io/badge/documentation-Corbado_Backend_API_Reference-blue.svg)](https://api.corbado.com/docs/api/)
[![Go Report Card](https://goreportcard.com/badge/github.com/corbado/corbado-go)](https://goreportcard.com/report/github.com/corbado/corbado-go)
+[![documentation](https://img.shields.io/badge/documentation-Corbado_Backend_API_Reference-blue.svg)](https://api.corbado.com/docs/api/)
+[![Slack](https://img.shields.io/badge/slack-join%20chat-brightgreen.svg)](https://join.slack.com/t/corbado/shared_invite/zt-1b7867yz8-V~Xr~ngmSGbt7IA~g16ZsQ)
-## Requirements
+The [Corbado](https://www.corbado.com) Go SDK provides convenient access to the [Corbado Backend API](https://api.corbado.com/docs/api/) from applications written in the Go language.
-The SDK supports Go version 1.18 and above.
+:warning: The Corbado Go SDK is commonly referred to as a private client, specifically designed for usage within closed backend applications. This particular SDK should exclusively be utilized in such environments, as it is crucial to ensure that the API secret remains strictly confidential and is never shared.
-## Usage
+:rocket: [Getting started](#rocket-getting-started) | :hammer_and_wrench: [Services](#hammer_and_wrench-services) | :books: [Advanced](#books-advanced) | :speech_balloon: [Support & Feedback](#speech_balloon-support--feedback)
+## :rocket: Getting started
+
+### Requirements
+
+- Go 1.18 or later
+
+### Installation
+
+Use the following command to install the Corbado Go SDK:
+
+```bash
+go get github.com/corbado/corbado-go@v1.0.0
```
-$ go get github.com/corbado/corbado-go@v0.6.0
-```
-Import SDK in your Go files:
+### Usage
+
+To create a Corbado Go SDK instance you need to provide your `Project ID` and `API secret` which can be found at the [Developer Panel](https://app.corbado.com).
+
+```Go
+package main
-```go
-import "github.com/corbado/corbado-go"
+import (
+ "github.com/corbado/corbado-go"
+)
+
+func main() {
+ config, err := corbado.NewConfig("", "")
+ if err != nil {
+ panic(err)
+ }
+
+ sdk, err := corbado.NewSDK(config)
+ if err != nil {
+ panic(err)
+ }
+}
```
-Now create a new SDK client:
+### Examples
+
+A list of examples can be found in the [examples](/examples) directory. [Integration tests](tests/integration) are good examples as well.
-```go
-config := corbado.MustNewConfig("pro-12345678", "yoursecret")
-sdk, err := corbado.NewSDK(config)
+## :hammer_and_wrench: Services
+
+The Corbado Go SDK provides the following services:
+
+- `AuthTokens` for managing authentication tokens needed for own session management ([examples](tests/integration/authtoken))
+- `EmailMagicLinks` for managing email magic links ([examples](tests/integration/emailmagiclink))
+- `EmailOTPs` for managing email OTPs ([examples](tests/integration/emailotp))
+- `Sessions` for managing sessions ([examples](examples/sessionstdlib))
+- `SmsOTPs` for managing SMS OTPs ([examples](tests/integration/smsotp))
+- `Users` for managing users ([examples](tests/integration/user))
+- `Validations` for validating email addresses and phone numbers ([examples](tests/integration/validation))
+
+To use a specific service, such as `Users`, invoke it as shown below:
+
+```Go
+users, err := sdk.Users().List(context.Background(), nil)
if err != nil {
- // handle error
+ panic(err)
}
+```
-// list all users
-users, err := sdk.Users().List(context.TODO(), nil)
-if err != nil {
- if serverErr := corbado.AsServerError(err); serverErr != nil {
- // handle server error
+## :books: Advanced
+
+### Error handling
+
+The Corbado Go SDK uses Go standard error handling (error interface). If the Backend API returns a HTTP status code other than 200, the Corbado Go SDK returns a `ServerError` error (which implements the error interface):
+
+```Go
+package main
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/corbado/corbado-go"
+)
+
+func main() {
+ config, err := corbado.NewConfig("", "")
+ if err != nil {
+ panic(err)
+ }
+
+ sdk, err := corbado.NewSDK(config)
+ if err != nil {
+ panic(err)
+ }
+
+ // Try to get non-existing user with ID 'usr-123456789'
+ user, err := sdk.Users().Get(context.Background(), "usr-123456789", nil)
+ if err != nil {
+ if serverErr := corbado.AsServerError(err); serverErr != nil {
+ // Show HTTP status code (404 in this case)
+ fmt.Println(serverErr.HTTPStatusCode)
+
+ // Show request ID (can be used in developer panel to look up the full request
+ // and response, see https://app.corbado.com/app/logs/requests)
+ fmt.Println(serverErr.RequestData.RequestID)
+
+ // Show runtime of request in seconds (server side)
+ fmt.Println(serverErr.Runtime)
+
+ // Show validation error messages (server side validation in case of HTTP
+ // status code 400 (Bad Request))
+ fmt.Printf("%+v\n", serverErr.Validation)
+ } else {
+ // Handle other errors
+ panic(err)
+ }
+
+ return
}
+
+ fmt.Println(user.Data.ID)
}
+
```
-See [examples](https://github.com/corbado/corbado-go/tree/main/examples) for some real example code
+## :speech_balloon: Support & Feedback
+
+### Report an issue
+
+If you encounter any bugs or have suggestions, please [open an issue](https://github.com/corbado/corbado-go/issues/new).
+
+### Slack channel
+
+Join our Slack channel to discuss questions or ideas with the Corbado team and other developers.
+
+[![Slack](https://img.shields.io/badge/slack-join%20chat-brightgreen.svg)](https://join.slack.com/t/corbado/shared_invite/zt-1b7867yz8-V~Xr~ngmSGbt7IA~g16ZsQ)
+
+### Email
+
+You can also reach out to us via email at vincent.delitz@corbado.com.
+
+### Vulnerability reporting
+
+Please report suspected security vulnerabilities in private to security@corbado.com. Please do NOT create publicly viewable issues for suspected security vulnerabilities.
diff --git a/Taskfile.yml b/Taskfile.yml
index af03ff1..36edab0 100644
--- a/Taskfile.yml
+++ b/Taskfile.yml
@@ -2,7 +2,7 @@ version: '3'
tasks:
lint:
- desc: Runs Golang linters
+ desc: Runs linters
cmds:
- GOFLAGS="-buildvcs=false" golangci-lint run --timeout=5m
sources:
@@ -10,15 +10,15 @@ tasks:
- ./.golangci.yml
method: checksum
- unit-test:
- desc: Runs Golang unit tests
+ unittests:
+ desc: Runs unit tests
cmds:
- go test -v ./...
- integration-test:
- desc: Runs Golang integration tests
+ integrationtests:
+ desc: Runs integration tests
cmds:
- - go test -tags=integration ./tests/integration/...
+ - go test -tags=integration -count=1 ./tests/integration/...
docker-build:
desc: Builds Docker image
diff --git a/client.go b/client.go
index a7efa74..0e5795d 100644
--- a/client.go
+++ b/client.go
@@ -3,19 +3,20 @@ package corbado
import (
"bytes"
"context"
- "fmt"
+ "encoding/json"
"io"
"net/http"
+ "runtime"
"github.com/corbado/corbado-go/pkg/logger"
- "github.com/corbado/corbado-go/pkg/sdk/assert"
- "github.com/corbado/corbado-go/pkg/sdk/config"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
"github.com/deepmap/oapi-codegen/pkg/securityprovider"
"github.com/pkg/errors"
+
+ "github.com/corbado/corbado-go/internal/assert"
+ "github.com/corbado/corbado-go/pkg/generated/api"
)
-func newClient(config *config.Config) (*api.ClientWithResponses, error) {
+func newClient(config *Config) (*api.ClientWithResponses, error) {
if err := assert.NotNil(config); err != nil {
return nil, err
}
@@ -26,7 +27,7 @@ func newClient(config *config.Config) (*api.ClientWithResponses, error) {
}
extraOptions := []api.ClientOption{
- api.WithRequestEditorFn(newSDKVersionHeaderEditorFn),
+ api.WithRequestEditorFn(newSDKHeaderEditorFn),
api.WithRequestEditorFn(basicAuth.Intercept),
}
@@ -113,8 +114,23 @@ func NewLoggingClientOption() api.ClientOption {
}
}
-func newSDKVersionHeaderEditorFn(_ context.Context, req *http.Request) error {
- req.Header.Set("X-Corbado-SDK-Version", fmt.Sprintf("Go SDK %s", Version))
+func newSDKHeaderEditorFn(_ context.Context, req *http.Request) error {
+ sdk := struct {
+ Name string `json:"name"`
+ SdkVersion string `json:"sdkVersion"`
+ LanguageVersion string `json:"languageVersion"`
+ }{
+ Name: "Go SDK",
+ SdkVersion: Version,
+ LanguageVersion: runtime.Version(),
+ }
+
+ marshaled, err := json.Marshal(sdk)
+ if err != nil {
+ return errors.WithStack(err)
+ }
+
+ req.Header.Set("X-Corbado-SDK", string(marshaled))
return nil
}
diff --git a/pkg/sdk/config/config.go b/config.go
similarity index 50%
rename from pkg/sdk/config/config.go
rename to config.go
index bcc4945..37fcc2e 100644
--- a/pkg/sdk/config/config.go
+++ b/config.go
@@ -1,12 +1,15 @@
-package config
+package corbado
import (
"fmt"
"net/http"
+ "os"
"time"
- "github.com/corbado/corbado-go/pkg/sdk/assert"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
+ "github.com/pkg/errors"
+
+ "github.com/corbado/corbado-go/internal/assert"
+ "github.com/corbado/corbado-go/pkg/generated/api"
)
type Config struct {
@@ -16,7 +19,6 @@ type Config struct {
BackendAPI string
ShortSessionCookieName string
CacheMaxAge time.Duration
- JWTIssuer string
JWKSRefreshInterval time.Duration
JWKSRefreshRateLimit time.Duration
@@ -50,8 +52,8 @@ func NewConfig(projectID string, apiSecret string) (*Config, error) {
return &Config{
ProjectID: projectID,
APISecret: apiSecret,
- BackendAPI: configDefaultBackendAPI,
FrontendAPI: fmt.Sprintf(configDefaultFrontendAPI, projectID),
+ BackendAPI: configDefaultBackendAPI,
ShortSessionCookieName: configDefaultShortSessionCookieName,
CacheMaxAge: configDefaultCacheMaxAge,
JWKSRefreshInterval: configDefaultJWKSRefreshInterval,
@@ -69,3 +71,58 @@ func MustNewConfig(projectID string, apiSecret string) *Config {
return config
}
+
+// NewConfigFromEnv returns new config with values from env variables (CORBADO_PROJECT_ID and CORBADO_API_SECRET)
+func NewConfigFromEnv() (*Config, error) {
+ projectID := os.Getenv("CORBADO_PROJECT_ID")
+ if projectID == "" {
+ return nil, errors.Errorf("Missing env variable CORBADO_PROJECT_ID")
+ }
+
+ apiSecret := os.Getenv("CORBADO_API_SECRET")
+ if apiSecret == "" {
+ return nil, errors.Errorf("Missing env variable CORBADO_API_SECRET")
+ }
+
+ return NewConfig(projectID, apiSecret)
+}
+
+func (c *Config) validate() error {
+ if err := assert.ValidProjectID(c.ProjectID); err != nil {
+ return errors.WithMessage(err, "Invalid ProjectID given")
+ }
+
+ if err := assert.ValidAPISecret(c.APISecret); err != nil {
+ return errors.WithMessage(err, "Invalid APISecret given")
+ }
+
+ if err := assert.ValidAPIEndpoint(c.FrontendAPI); err != nil {
+ return errors.WithMessage(err, "Invalid FrontendAPI given")
+ }
+
+ if err := assert.ValidAPIEndpoint(c.BackendAPI); err != nil {
+ return errors.WithMessage(err, "Invalid BackendAPI given")
+ }
+
+ if err := assert.StringNotEmpty(c.ShortSessionCookieName); err != nil {
+ return errors.WithMessage(err, "Invalid ShortSessionCookieName given")
+ }
+
+ if err := assert.DurationNotEmpty(c.CacheMaxAge); err != nil {
+ return errors.WithMessage(err, "Invalid CacheMaxAge given")
+ }
+
+ if err := assert.DurationNotEmpty(c.JWKSRefreshInterval); err != nil {
+ return errors.WithMessage(err, "Invalid JWKSRefreshInterval given")
+ }
+
+ if err := assert.DurationNotEmpty(c.JWKSRefreshRateLimit); err != nil {
+ return errors.WithMessage(err, "Invalid JWKSRefreshRateLimit given")
+ }
+
+ if err := assert.DurationNotEmpty(c.JWKSRefreshTimeout); err != nil {
+ return errors.WithMessage(err, "Invalid JWKSRefreshTimeout given")
+ }
+
+ return nil
+}
diff --git a/pkg/sdk/config/config_test.go b/config_test.go
similarity index 98%
rename from pkg/sdk/config/config_test.go
rename to config_test.go
index 95ec301..6c3eeec 100644
--- a/pkg/sdk/config/config_test.go
+++ b/config_test.go
@@ -1,4 +1,4 @@
-package config
+package corbado
import (
"fmt"
diff --git a/examples/basic/main.go b/examples/basic/main.go
index 1836971..46dfebf 100644
--- a/examples/basic/main.go
+++ b/examples/basic/main.go
@@ -8,7 +8,13 @@ import (
)
func main() {
- config := corbado.MustNewConfig("pro-12345678", "yoursecret")
+ // NewConfigFromEnv() reads project ID and API secret from CORBADO_PROJECT_ID
+ // and CORBADO_API_SECRET environment variables
+ config, err := corbado.NewConfigFromEnv()
+ if err != nil {
+ panic(err)
+ }
+
sdk, err := corbado.NewSDK(config)
if err != nil {
panic(err)
diff --git a/examples/sessionstdlib/main.go b/examples/sessionstdlib/main.go
new file mode 100644
index 0000000..9a5c9d6
--- /dev/null
+++ b/examples/sessionstdlib/main.go
@@ -0,0 +1,68 @@
+package main
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/stdlib"
+)
+
+func main() {
+ // NewConfigFromEnv() reads project ID and API secret from CORBADO_PROJECT_ID
+ // and CORBADO_API_SECRET environment variables
+ config, err := corbado.NewConfigFromEnv()
+ if err != nil {
+ panic(err)
+ }
+
+ sdk, err := corbado.NewSDK(config)
+ if err != nil {
+ panic(err)
+ }
+
+ sdkHelpers, err := stdlib.NewSDKHelpers(config)
+ if err != nil {
+ panic(err)
+ }
+
+ http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ shortSession, err := sdkHelpers.GetShortSessionValue(r)
+ if err != nil {
+ panic(err)
+ }
+
+ user, err := sdk.Sessions().GetCurrentUser(shortSession)
+ if err != nil {
+ panic(err)
+ }
+
+ if user.Authenticated {
+ // User is authenticated
+ fmt.Fprint(w, "User is authenticated!")
+
+ fmt.Fprintf(w, "User ID: %s\n", user.ID)
+ fmt.Fprintf(w, "User full name: %s\n", user.Name)
+ fmt.Fprintf(w, "User email: %s\n", user.Email)
+ fmt.Fprintf(w, "User phone number: %s\n", user.PhoneNumber)
+
+ rsp, err := sdk.Users().Get(context.Background(), user.ID, nil)
+ if err != nil {
+ panic(err)
+ }
+
+ fmt.Fprintf(w, "User created: %s\n", rsp.Data.Created)
+ fmt.Fprintf(w, "User updated: %s\n", rsp.Data.Updated)
+ fmt.Fprintf(w, "User status: %s\n", rsp.Data.Status)
+ } else {
+ // User is not authenticated, redirect to login
+ // page for example
+ http.Redirect(w, r, "/login", http.StatusFound)
+ }
+ })
+
+ if err := http.ListenAndServe(":8080", nil); err != nil {
+ panic(err)
+ }
+}
diff --git a/internal/assert/assert.go b/internal/assert/assert.go
new file mode 100644
index 0000000..16b8fa3
--- /dev/null
+++ b/internal/assert/assert.go
@@ -0,0 +1,151 @@
+package assert
+
+import (
+ "fmt"
+ "net/url"
+ "reflect"
+ "time"
+
+ "github.com/pkg/errors"
+)
+
+// NotNil checks given value if it is not nil
+func NotNil(values ...any) error {
+ for i, value := range values {
+ if value == nil {
+ return errors.WithStack(fmt.Errorf("assert failed: given value at index %d is nil", i))
+ }
+
+ switch reflect.TypeOf(value).Kind() {
+ case reflect.Ptr, reflect.Map, reflect.Array, reflect.Chan, reflect.Slice, reflect.Func:
+ if reflect.ValueOf(value).IsNil() {
+ return errors.WithStack(fmt.Errorf("assert failed: given value at index %d is nil", i))
+ }
+ }
+ }
+
+ return nil
+}
+
+// StringLength checks a string for the given min and max length
+func StringLength(value string, minLength int, maxLength int, allowedValues *[]string /* can be nil */) error {
+ if minLength != -1 && maxLength != -1 && minLength > maxLength {
+ return errors.Errorf("assert misuse: minLength should be smaller than maxLength (minLength: %d, maxLength: %d)", minLength, maxLength)
+ }
+
+ lenString := len(value)
+ if minLength != -1 && lenString < minLength {
+ return errors.Errorf("assert failed: given value '%s' is too short (%d < %d)", value, lenString, minLength)
+ }
+
+ if maxLength != -1 && lenString > maxLength {
+ return errors.Errorf("assert failed: given value '%s' is too long (%d > %d)", value, lenString, minLength)
+ }
+
+ if allowedValues != nil {
+ found := false
+ for _, allowedValue := range *allowedValues {
+ if allowedValue == value {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ return errors.Errorf("assert failed: given value '%s' is not in allowed values (%s)", value, *allowedValues)
+ }
+ }
+
+ return nil
+}
+
+// StringNotEmpty checks if given string is not empty
+func StringNotEmpty(value string) error {
+ return StringLength(value, 1, -1, nil)
+}
+
+// ValidProjectID check if given string is a valid project ID
+func ValidProjectID(value string) error {
+ if err := StringNotEmpty(value); err != nil {
+ return err
+ }
+
+ if len(value) < 5 {
+ return errors.Errorf("assert failed: given value '%s' is too short", value)
+ }
+
+ if value[:4] != "pro-" {
+ return errors.Errorf("assert failed: given value '%s' does not start with 'pro-'", value)
+ }
+
+ return nil
+}
+
+// ValidAPISecret checks if given string isa valid API secret
+func ValidAPISecret(value string) error {
+ if err := StringNotEmpty(value); err != nil {
+ return err
+ }
+
+ if len(value) < 10 {
+ return errors.Errorf("assert failed: given value '%s' is too short", value)
+ }
+
+ if value[:9] != "corbado1_" {
+ return errors.Errorf("assert failed: given value '%s' does not start with 'corbado1_'", value)
+ }
+
+ return nil
+}
+
+// ValidAPIEndpoint check if given string is a valid API endpoint
+func ValidAPIEndpoint(value string) error {
+ if err := StringNotEmpty(value); err != nil {
+ return err
+ }
+
+ u, err := url.Parse(value)
+ if err != nil {
+ return errors.WithStack(err)
+ }
+
+ if u.Scheme != "https" {
+ return errors.Errorf("assert failed: scheme needs to be 'https' in given value '%s' (scheme: '%s')", value, u.Scheme)
+ }
+
+ if u.Host == "" {
+ return errors.Errorf("assert failed: host must not be empty in given value '%s'", value)
+ }
+
+ if u.User.Username() != "" {
+ return errors.Errorf("assert failed: username must be empty in given value '%s' (username: '%s')", value, u.User.Username())
+ }
+
+ password, _ := u.User.Password()
+ if password != "" {
+ return errors.Errorf("assert failed: password must be empty in given value '%s' (password: '%s')", value, password)
+ }
+
+ if u.Path != "" {
+ return errors.Errorf("assert failed: path must be empty in given value '%s' (path: '%s')", value, u.Path)
+ }
+
+ if u.Fragment != "" {
+ return errors.Errorf("assert failed: fragment must be empty in given value '%s' (fragment: '%s')", value, u.Fragment)
+ }
+
+ if u.RawQuery != "" {
+ return errors.Errorf("assert failed: querystring must be empty in given value '%s' (querystring: '%s')", value, u.RawQuery)
+ }
+
+ return nil
+}
+
+// DurationNotEmpty checks if given duration is not empty
+func DurationNotEmpty(value time.Duration) error {
+ if value == 0 {
+ return errors.Errorf("assert failed: given value '%s' is empty", value)
+ }
+
+ return nil
+}
diff --git a/pkg/sdk/authtoken/authtoken.go b/internal/services/authtoken/authtoken.go
similarity index 79%
rename from pkg/sdk/authtoken/authtoken.go
rename to internal/services/authtoken/authtoken.go
index 4622551..0ade10f 100644
--- a/pkg/sdk/authtoken/authtoken.go
+++ b/internal/services/authtoken/authtoken.go
@@ -3,9 +3,11 @@ package authtoken
import (
"context"
- "github.com/corbado/corbado-go/pkg/sdk/assert"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
+ "github.com/pkg/errors"
+
+ "github.com/corbado/corbado-go/internal/assert"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
)
type AuthToken interface {
@@ -32,7 +34,7 @@ func New(client *api.ClientWithResponses) (*Impl, error) {
func (i *Impl) Validate(ctx context.Context, req api.AuthTokenValidateReq, editors ...api.RequestEditorFn) (*api.AuthTokenValidateRsp, error) {
res, err := i.client.AuthTokenValidateWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
diff --git a/pkg/sdk/emaillink/emaillinks.go b/internal/services/emailmagiclink/emailmagiclink.go
similarity index 74%
rename from pkg/sdk/emaillink/emaillinks.go
rename to internal/services/emailmagiclink/emailmagiclink.go
index 2d4717e..23f4a5d 100644
--- a/pkg/sdk/emaillink/emaillinks.go
+++ b/internal/services/emailmagiclink/emailmagiclink.go
@@ -1,15 +1,17 @@
-package emaillink
+package emailmagiclink
import (
"context"
- "github.com/corbado/corbado-go/pkg/sdk/assert"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/entity/common"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
+ "github.com/pkg/errors"
+
+ "github.com/corbado/corbado-go/internal/assert"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/generated/common"
+ "github.com/corbado/corbado-go/pkg/servererror"
)
-type EmailLink interface {
+type EmailMagicLink interface {
Send(ctx context.Context, req api.EmailLinkSendReq, editors ...api.RequestEditorFn) (*api.EmailLinkSendRsp, error)
Validate(ctx context.Context, emailLinkID common.EmailLinkID, req api.EmailLinksValidateReq, editors ...api.RequestEditorFn) (*api.EmailLinkValidateRsp, error)
Get(ctx context.Context, emailLinkID common.EmailLinkID, editors ...api.RequestEditorFn) (*api.EmailLinkGetRsp, error)
@@ -19,9 +21,9 @@ type Impl struct {
client *api.ClientWithResponses
}
-var _ EmailLink = &Impl{}
+var _ EmailMagicLink = &Impl{}
-// New returns new email link client
+// New returns new email magic link client
func New(client *api.ClientWithResponses) (*Impl, error) {
if err := assert.NotNil(client); err != nil {
return nil, err
@@ -32,11 +34,11 @@ func New(client *api.ClientWithResponses) (*Impl, error) {
}, nil
}
-// Send sends email link email to given email address
+// Send sends email magic link email to given email address
func (i *Impl) Send(ctx context.Context, req api.EmailLinkSendReq, editors ...api.RequestEditorFn) (*api.EmailLinkSendRsp, error) {
res, err := i.client.EmailLinkSendWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -46,11 +48,11 @@ func (i *Impl) Send(ctx context.Context, req api.EmailLinkSendReq, editors ...ap
return res.JSON200, nil
}
-// Validate validates email link token
+// Validate validates email magic link token
func (i *Impl) Validate(ctx context.Context, emailLinkID common.EmailLinkID, req api.EmailLinksValidateReq, editors ...api.RequestEditorFn) (*api.EmailLinkValidateRsp, error) {
res, err := i.client.EmailLinkValidateWithResponse(ctx, emailLinkID, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -60,11 +62,11 @@ func (i *Impl) Validate(ctx context.Context, emailLinkID common.EmailLinkID, req
return res.JSON200, nil
}
-// Get gets email link
+// Get gets email magic link
func (i *Impl) Get(ctx context.Context, emailLinkID common.EmailLinkID, editors ...api.RequestEditorFn) (*api.EmailLinkGetRsp, error) {
res, err := i.client.EmailLinkGetWithResponse(ctx, emailLinkID, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
diff --git a/pkg/sdk/emailcode/emailcodes.go b/internal/services/emailotp/emailotp.go
similarity index 75%
rename from pkg/sdk/emailcode/emailcodes.go
rename to internal/services/emailotp/emailotp.go
index 8a1a6f5..465cf34 100644
--- a/pkg/sdk/emailcode/emailcodes.go
+++ b/internal/services/emailotp/emailotp.go
@@ -1,15 +1,17 @@
-package emailcode
+package emailotp
import (
"context"
- "github.com/corbado/corbado-go/pkg/sdk/assert"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/entity/common"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
+ "github.com/pkg/errors"
+
+ "github.com/corbado/corbado-go/internal/assert"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/generated/common"
+ "github.com/corbado/corbado-go/pkg/servererror"
)
-type EmailCode interface {
+type EmailOTP interface {
Send(ctx context.Context, req api.EmailCodeSendReq, editors ...api.RequestEditorFn) (*api.EmailCodeSendRsp, error)
Validate(ctx context.Context, emailCodeID common.EmailCodeID, req api.EmailCodeValidateReq, editors ...api.RequestEditorFn) (*api.EmailCodeValidateRsp, error)
Get(ctx context.Context, emailCodeID common.EmailCodeID, editors ...api.RequestEditorFn) (*api.EmailCodeGetRsp, error)
@@ -19,9 +21,9 @@ type Impl struct {
client *api.ClientWithResponses
}
-var _ EmailCode = &Impl{}
+var _ EmailOTP = &Impl{}
-// New returns new email code client
+// New returns new email OTP client
func New(client *api.ClientWithResponses) (*Impl, error) {
if err := assert.NotNil(client); err != nil {
return nil, err
@@ -32,11 +34,11 @@ func New(client *api.ClientWithResponses) (*Impl, error) {
}, nil
}
-// Send sends email code email to given email address
+// Send sends OTP email to given email address
func (i *Impl) Send(ctx context.Context, req api.EmailCodeSendReq, editors ...api.RequestEditorFn) (*api.EmailCodeSendRsp, error) {
res, err := i.client.EmailCodeSendWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -46,11 +48,11 @@ func (i *Impl) Send(ctx context.Context, req api.EmailCodeSendReq, editors ...ap
return res.JSON200, nil
}
-// Validate validates email code token
+// Validate validates email OTP
func (i *Impl) Validate(ctx context.Context, emailCodeID common.EmailCodeID, req api.EmailCodeValidateReq, editors ...api.RequestEditorFn) (*api.EmailCodeValidateRsp, error) {
res, err := i.client.EmailCodeValidateWithResponse(ctx, emailCodeID, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -60,11 +62,11 @@ func (i *Impl) Validate(ctx context.Context, emailCodeID common.EmailCodeID, req
return res.JSON200, nil
}
-// Get gets email code
+// Get gets email OTP
func (i *Impl) Get(ctx context.Context, emailCodeID common.EmailCodeID, editors ...api.RequestEditorFn) (*api.EmailCodeGetRsp, error) {
res, err := i.client.EmailCodeGetWithResponse(ctx, emailCodeID, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
diff --git a/pkg/sdk/passkey/passkeys.go b/internal/services/passkey/passkeys.go
similarity index 92%
rename from pkg/sdk/passkey/passkeys.go
rename to internal/services/passkey/passkeys.go
index cbf104c..5f48b6c 100644
--- a/pkg/sdk/passkey/passkeys.go
+++ b/internal/services/passkey/passkeys.go
@@ -3,9 +3,11 @@ package passkey
import (
"context"
- "github.com/corbado/corbado-go/pkg/sdk/assert"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
+ "github.com/pkg/errors"
+
+ "github.com/corbado/corbado-go/internal/assert"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
)
type Passkey interface {
@@ -42,7 +44,7 @@ func New(client *api.ClientWithResponses) (*Impl, error) {
func (i *Impl) CreateSecret(ctx context.Context, req api.ProjectSecretCreateReq, editors ...api.RequestEditorFn) (*api.ProjectSecretCreateRsp, error) {
res, err := i.client.ProjectSecretCreateWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -56,7 +58,7 @@ func (i *Impl) CreateSecret(ctx context.Context, req api.ProjectSecretCreateReq,
func (i *Impl) RegisterStart(ctx context.Context, req api.WebAuthnRegisterStartReq, editors ...api.RequestEditorFn) (*api.WebAuthnRegisterStartRsp, error) {
res, err := i.client.WebAuthnRegisterStartWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -70,7 +72,7 @@ func (i *Impl) RegisterStart(ctx context.Context, req api.WebAuthnRegisterStartR
func (i *Impl) RegisterFinish(ctx context.Context, req api.WebAuthnFinishReq, editors ...api.RequestEditorFn) (*api.WebAuthnRegisterFinishRsp, error) {
res, err := i.client.WebAuthnRegisterFinishWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -84,7 +86,7 @@ func (i *Impl) RegisterFinish(ctx context.Context, req api.WebAuthnFinishReq, ed
func (i *Impl) AuthenticateStart(ctx context.Context, req api.WebAuthnAuthenticateStartReq, editors ...api.RequestEditorFn) (*api.WebAuthnAuthenticateStartRsp, error) {
res, err := i.client.WebAuthnAuthenticateStartWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -98,7 +100,7 @@ func (i *Impl) AuthenticateStart(ctx context.Context, req api.WebAuthnAuthentica
func (i *Impl) AuthenticateFinish(ctx context.Context, req api.WebAuthnFinishReq, editors ...api.RequestEditorFn) (*api.WebAuthnAuthenticateFinishRsp, error) {
res, err := i.client.WebAuthnAuthenticateFinishWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -112,7 +114,7 @@ func (i *Impl) AuthenticateFinish(ctx context.Context, req api.WebAuthnFinishReq
func (i *Impl) MediationStart(ctx context.Context, req api.WebAuthnMediationStartReq, editors ...api.RequestEditorFn) (*api.WebAuthnMediationStartRsp, error) {
res, err := i.client.WebAuthnMediationStartWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -126,7 +128,7 @@ func (i *Impl) MediationStart(ctx context.Context, req api.WebAuthnMediationStar
func (i *Impl) AssociateStart(ctx context.Context, req api.WebAuthnAssociateStartReq, editors ...api.RequestEditorFn) (*api.WebAuthnAssociateStartRsp, error) {
res, err := i.client.WebAuthnAssociateStartWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -140,7 +142,7 @@ func (i *Impl) AssociateStart(ctx context.Context, req api.WebAuthnAssociateStar
func (i *Impl) CredentialList(ctx context.Context, params *api.WebAuthnCredentialListParams, editors ...api.RequestEditorFn) (*api.WebAuthnCredentialListRsp, error) {
res, err := i.client.WebAuthnCredentialListWithResponse(ctx, params, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -154,7 +156,7 @@ func (i *Impl) CredentialList(ctx context.Context, params *api.WebAuthnCredentia
func (i *Impl) CredentialUpdate(ctx context.Context, credentialID string, req api.WebAuthnCredentialReq, editors ...api.RequestEditorFn) (*api.WebAuthnCredentialRsp, error) {
res, err := i.client.WebAuthnCredentialUpdateWithResponse(ctx, credentialID, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -168,7 +170,7 @@ func (i *Impl) CredentialUpdate(ctx context.Context, credentialID string, req ap
func (i *Impl) CredentialExists(ctx context.Context, req api.WebAuthnCredentialExistsReq, editors ...api.RequestEditorFn) (*api.WebAuthnCredentialExistsRsp, error) {
res, err := i.client.WebAuthnCredentialExistsWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -182,7 +184,7 @@ func (i *Impl) CredentialExists(ctx context.Context, req api.WebAuthnCredentialE
func (i *Impl) CredentialDelete(ctx context.Context, userID string, credentialID string, req api.EmptyReq, editors ...api.RequestEditorFn) error {
res, err := i.client.WebAuthnCredentialDeleteWithResponse(ctx, userID, credentialID, req, editors...)
if err != nil {
- return err
+ return errors.WithStack(err)
}
if res.JSONDefault != nil {
diff --git a/pkg/sdk/project/project.go b/internal/services/project/project.go
similarity index 89%
rename from pkg/sdk/project/project.go
rename to internal/services/project/project.go
index 983b5f7..50d8a37 100644
--- a/pkg/sdk/project/project.go
+++ b/internal/services/project/project.go
@@ -3,9 +3,11 @@ package project
import (
"context"
- "github.com/corbado/corbado-go/pkg/sdk/assert"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
+ "github.com/pkg/errors"
+
+ "github.com/corbado/corbado-go/internal/assert"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
)
type Project interface {
@@ -38,7 +40,7 @@ func New(client *api.ClientWithResponses) (*Impl, error) {
func (i *Impl) CreateSecret(ctx context.Context, req api.ProjectSecretCreateReq, editors ...api.RequestEditorFn) (*api.ProjectSecretCreateRsp, error) {
res, err := i.client.ProjectSecretCreateWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -52,7 +54,7 @@ func (i *Impl) CreateSecret(ctx context.Context, req api.ProjectSecretCreateReq,
func (i *Impl) ConfigGet(ctx context.Context, editors ...api.RequestEditorFn) (*api.ProjectConfigGetRsp, error) {
res, err := i.client.ProjectConfigGetWithResponse(ctx, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -66,7 +68,7 @@ func (i *Impl) ConfigGet(ctx context.Context, editors ...api.RequestEditorFn) (*
func (i *Impl) ConfigUpdate(ctx context.Context, req api.ProjectConfigSaveReq, editors ...api.RequestEditorFn) error {
res, err := i.client.ProjectConfigSaveWithResponse(ctx, req, editors...)
if err != nil {
- return err
+ return errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -80,7 +82,7 @@ func (i *Impl) ConfigUpdate(ctx context.Context, req api.ProjectConfigSaveReq, e
func (i *Impl) AuthMethodsList(ctx context.Context, req api.AuthMethodsListReq, editors ...api.RequestEditorFn) (*api.AuthMethodsListRsp, error) {
res, err := i.client.AuthMethodsListWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -94,7 +96,7 @@ func (i *Impl) AuthMethodsList(ctx context.Context, req api.AuthMethodsListReq,
func (i *Impl) AndroidAppConfigGet(ctx context.Context, editors ...api.RequestEditorFn) (*api.AndroidAppConfigListRsp, error) {
res, err := i.client.AndroidAppConfigGetWithResponse(ctx, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -108,7 +110,7 @@ func (i *Impl) AndroidAppConfigGet(ctx context.Context, editors ...api.RequestEd
func (i *Impl) IOSAppConfigGet(ctx context.Context, editors ...api.RequestEditorFn) (*api.IOSAppConfigListRsp, error) {
res, err := i.client.IOSAppConfigGetWithResponse(ctx, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
diff --git a/internal/services/session/config.go b/internal/services/session/config.go
new file mode 100644
index 0000000..cb10268
--- /dev/null
+++ b/internal/services/session/config.go
@@ -0,0 +1,46 @@
+package session
+
+import (
+ "time"
+
+ "github.com/pkg/errors"
+
+ "github.com/corbado/corbado-go/internal/assert"
+)
+
+type Config struct {
+ ProjectID string
+ JWTIssuer string
+ JwksURI string
+ JWKSRefreshInterval time.Duration
+ JWKSRefreshRateLimit time.Duration
+ JWKSRefreshTimeout time.Duration
+}
+
+func (c *Config) validate() error {
+ if err := assert.ValidProjectID(c.ProjectID); err != nil {
+ return errors.WithMessage(err, "Invalid ProjectID given")
+ }
+
+ if err := assert.ValidAPIEndpoint(c.JWTIssuer); err != nil {
+ return errors.WithMessage(err, "Invalid JWTIssuer given")
+ }
+
+ if err := assert.StringNotEmpty(c.JwksURI); err != nil {
+ return errors.WithMessage(err, "Invalid JwksURI given")
+ }
+
+ if err := assert.DurationNotEmpty(c.JWKSRefreshInterval); err != nil {
+ return errors.WithMessage(err, "Invalid JWKSRefreshInterval given")
+ }
+
+ if err := assert.DurationNotEmpty(c.JWKSRefreshRateLimit); err != nil {
+ return errors.WithMessage(err, "Invalid JWKSRefreshRateLimit given")
+ }
+
+ if err := assert.DurationNotEmpty(c.JWKSRefreshTimeout); err != nil {
+ return errors.WithMessage(err, "Invalid JWKSRefreshTimeout given")
+ }
+
+ return nil
+}
diff --git a/pkg/sdk/session/session.go b/internal/services/session/session.go
similarity index 76%
rename from pkg/sdk/session/session.go
rename to internal/services/session/session.go
index a1224c1..95ccaf3 100644
--- a/pkg/sdk/session/session.go
+++ b/internal/services/session/session.go
@@ -3,25 +3,24 @@ package session
import (
"context"
"encoding/json"
- "fmt"
"io"
"net/http"
"net/url"
"github.com/MicahParks/keyfunc"
"github.com/corbado/corbado-go/pkg/logger"
- "github.com/corbado/corbado-go/pkg/sdk/assert"
- "github.com/corbado/corbado-go/pkg/sdk/config"
- "github.com/corbado/corbado-go/pkg/sdk/entity"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
"github.com/golang-jwt/jwt/v4"
"github.com/pkg/errors"
+
+ "github.com/corbado/corbado-go/internal/assert"
+ entities2 "github.com/corbado/corbado-go/pkg/entities"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
)
type Session interface {
- ValidateShortSessionValue(shortSession string) (*entity.User, error)
- GetCurrentUser(shortSession string) (*entity.User, error)
+ ValidateShortSessionValue(shortSession string) (*entities2.User, error)
+ GetCurrentUser(shortSession string) (*entities2.User, error)
ConfigGet(ctx context.Context, params *api.SessionConfigGetParams, editors ...api.RequestEditorFn) (*api.SessionConfigGetRsp, error)
LongSessionRevoke(ctx context.Context, sessionID string, req api.LongSessionRevokeReq, editors ...api.RequestEditorFn) error
LongSessionGet(ctx context.Context, sessionID string, editors ...api.RequestEditorFn) (*api.LongSessionGetRsp, error)
@@ -29,25 +28,29 @@ type Session interface {
type Impl struct {
client *api.ClientWithResponses
- config *config.Config
+ config *Config
jwks *keyfunc.JWKS
}
var _ Session = &Impl{}
// New returns new user client
-func New(client *api.ClientWithResponses, config *config.Config) (*Impl, error) {
+func New(client *api.ClientWithResponses, config *Config) (*Impl, error) {
if err := assert.NotNil(client, config); err != nil {
return nil, err
}
+ if err := config.validate(); err != nil {
+ return nil, err
+ }
+
return &Impl{
client: client,
config: config,
}, nil
}
-func newJWKS(config *config.Config) (*keyfunc.JWKS, error) {
+func newJWKS(config *Config) (*keyfunc.JWKS, error) {
options := keyfunc.Options{
RequestFactory: func(ctx context.Context, urlAddress string) (*http.Request, error) {
address, err := url.Parse(urlAddress)
@@ -82,10 +85,10 @@ func newJWKS(config *config.Config) (*keyfunc.JWKS, error) {
RefreshUnknownKID: true,
}
- return keyfunc.Get(fmt.Sprintf("%s/.well-known/jwks", config.FrontendAPI), options)
+ return keyfunc.Get(config.JwksURI, options)
}
-func (i *Impl) ValidateShortSessionValue(shortSession string) (*entity.User, error) {
+func (i *Impl) ValidateShortSessionValue(shortSession string) (*entities2.User, error) {
if shortSession == "" {
return nil, nil
}
@@ -99,17 +102,17 @@ func (i *Impl) ValidateShortSessionValue(shortSession string) (*entity.User, err
i.jwks = jwks
}
- token, err := jwt.ParseWithClaims(shortSession, &entity.Claims{}, i.jwks.Keyfunc)
+ token, err := jwt.ParseWithClaims(shortSession, &entities2.Claims{}, i.jwks.Keyfunc)
if err != nil {
return nil, errors.WithStack(err)
}
- claims := token.Claims.(*entity.Claims)
- if i.config.JWTIssuer != "" && claims.Issuer != i.config.JWTIssuer {
- return nil, errors.Errorf("JWT issuer mismatch (configured for Frontend API: '%s', actual JWT: '%s')", i.config.JWTIssuer, claims.Issuer)
+ claims := token.Claims.(*entities2.Claims)
+ if claims.Issuer != i.config.JWTIssuer {
+ return nil, errors.Errorf("JWT issuer mismatch (configured: '%s', actual JWT: '%s')", i.config.JWTIssuer, claims.Issuer)
}
- return &entity.User{
+ return &entities2.User{
Authenticated: true,
ID: claims.Subject,
Name: claims.Name,
@@ -118,7 +121,7 @@ func (i *Impl) ValidateShortSessionValue(shortSession string) (*entity.User, err
}, nil
}
-func (i *Impl) GetCurrentUser(shortSession string) (*entity.User, error) {
+func (i *Impl) GetCurrentUser(shortSession string) (*entities2.User, error) {
usr, err := i.ValidateShortSessionValue(shortSession)
if err != nil {
return nil, err
@@ -128,14 +131,14 @@ func (i *Impl) GetCurrentUser(shortSession string) (*entity.User, error) {
return usr, nil
}
- return entity.NewGuestUser(), nil
+ return entities2.NewGuestUser(), nil
}
// ConfigGet retrieves session config by projectID inferred from authentication
func (i *Impl) ConfigGet(ctx context.Context, params *api.SessionConfigGetParams, editors ...api.RequestEditorFn) (*api.SessionConfigGetRsp, error) {
res, err := i.client.SessionConfigGetWithResponse(ctx, params, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -149,7 +152,7 @@ func (i *Impl) ConfigGet(ctx context.Context, params *api.SessionConfigGetParams
func (i *Impl) LongSessionRevoke(ctx context.Context, sessionID string, req api.LongSessionRevokeReq, editors ...api.RequestEditorFn) error {
res, err := i.client.LongSessionRevokeWithResponse(ctx, sessionID, req, editors...)
if err != nil {
- return err
+ return errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -163,7 +166,7 @@ func (i *Impl) LongSessionRevoke(ctx context.Context, sessionID string, req api.
func (i *Impl) LongSessionGet(ctx context.Context, sessionID string, editors ...api.RequestEditorFn) (*api.LongSessionGetRsp, error) {
res, err := i.client.LongSessionGetWithResponse(ctx, sessionID, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
diff --git a/internal/services/smsotp/smsotp.go b/internal/services/smsotp/smsotp.go
new file mode 100644
index 0000000..6556bbc
--- /dev/null
+++ b/internal/services/smsotp/smsotp.go
@@ -0,0 +1,61 @@
+package smsotp
+
+import (
+ "context"
+
+ "github.com/pkg/errors"
+
+ "github.com/corbado/corbado-go/internal/assert"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+)
+
+type SmsOTP interface {
+ Send(ctx context.Context, req api.SmsCodeSendReq, editors ...api.RequestEditorFn) (*api.SmsCodeSendRsp, error)
+ Validate(ctx context.Context, emailCodeID api.SmsCodeID, req api.SmsCodeValidateReq, editors ...api.RequestEditorFn) (*api.SmsCodeValidateRsp, error)
+}
+
+type Impl struct {
+ client *api.ClientWithResponses
+}
+
+var _ SmsOTP = &Impl{}
+
+// New returns new SMS OTP client
+func New(client *api.ClientWithResponses) (*Impl, error) {
+ if err := assert.NotNil(client); err != nil {
+ return nil, err
+ }
+
+ return &Impl{
+ client: client,
+ }, nil
+}
+
+// Send sends OTP SMS to given phone number
+func (i *Impl) Send(ctx context.Context, req api.SmsCodeSendReq, editors ...api.RequestEditorFn) (*api.SmsCodeSendRsp, error) {
+ res, err := i.client.SmsCodeSendWithResponse(ctx, req, editors...)
+ if err != nil {
+ return nil, errors.WithStack(err)
+ }
+
+ if res.JSONDefault != nil {
+ return nil, servererror.New(res.JSONDefault)
+ }
+
+ return res.JSON200, nil
+}
+
+// Validate validates SMS OTP
+func (i *Impl) Validate(ctx context.Context, smsCodeID api.SmsCodeID, req api.SmsCodeValidateReq, editors ...api.RequestEditorFn) (*api.SmsCodeValidateRsp, error) {
+ res, err := i.client.SmsCodeValidateWithResponse(ctx, smsCodeID, req, editors...)
+ if err != nil {
+ return nil, errors.WithStack(err)
+ }
+
+ if res.JSONDefault != nil {
+ return nil, servererror.New(res.JSONDefault)
+ }
+
+ return res.JSON200, nil
+}
diff --git a/pkg/sdk/template/template.go b/internal/services/template/template.go
similarity index 85%
rename from pkg/sdk/template/template.go
rename to internal/services/template/template.go
index ed7708e..ee55d8a 100644
--- a/pkg/sdk/template/template.go
+++ b/internal/services/template/template.go
@@ -3,9 +3,11 @@ package template
import (
"context"
- "github.com/corbado/corbado-go/pkg/sdk/assert"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
+ "github.com/pkg/errors"
+
+ "github.com/corbado/corbado-go/internal/assert"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
)
type Template interface {
@@ -34,7 +36,7 @@ func New(client *api.ClientWithResponses) (*Impl, error) {
func (i *Impl) CreateEmailTemplate(ctx context.Context, req api.EmailTemplateCreateReq, editors ...api.RequestEditorFn) (*api.EmailTemplateCreateRsp, error) {
res, err := i.client.EmailTemplateCreateWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -48,7 +50,7 @@ func (i *Impl) CreateEmailTemplate(ctx context.Context, req api.EmailTemplateCre
func (i *Impl) CreateSMSTemplate(ctx context.Context, req api.SmsTemplateCreateReq, editors ...api.RequestEditorFn) (*api.SmsTemplateCreateRsp, error) {
res, err := i.client.SmsTemplateCreateWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
diff --git a/pkg/sdk/user/user.go b/internal/services/user/user.go
similarity index 70%
rename from pkg/sdk/user/user.go
rename to internal/services/user/user.go
index e1d6072..cfbc98d 100644
--- a/pkg/sdk/user/user.go
+++ b/internal/services/user/user.go
@@ -3,10 +3,12 @@ package user
import (
"context"
- "github.com/corbado/corbado-go/pkg/sdk/assert"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/entity/common"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
+ "github.com/pkg/errors"
+
+ "github.com/corbado/corbado-go/internal/assert"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/generated/common"
+ "github.com/corbado/corbado-go/pkg/servererror"
)
type User interface {
@@ -14,6 +16,7 @@ type User interface {
Update(ctx context.Context, userID common.UserID, req api.UserUpdateReq, editors ...api.RequestEditorFn) (*api.UserUpdateRsp, error)
Create(ctx context.Context, req api.UserCreateReq, editors ...api.RequestEditorFn) (*api.UserCreateRsp, error)
Get(ctx context.Context, userID common.UserID, params *api.UserGetParams, editors ...api.RequestEditorFn) (*api.UserGetRsp, error)
+ Delete(ctx context.Context, userID common.UserID, req api.UserDeleteReq, editors ...api.RequestEditorFn) (*common.GenericRsp, error)
}
type Impl struct {
@@ -33,11 +36,11 @@ func New(client *api.ClientWithResponses) (*Impl, error) {
}, nil
}
-// List lists project users
+// List lists users
func (i *Impl) List(ctx context.Context, params *api.UserListParams, editors ...api.RequestEditorFn) (*api.UserListRsp, error) {
res, err := i.client.UserListWithResponse(ctx, params, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -51,7 +54,7 @@ func (i *Impl) List(ctx context.Context, params *api.UserListParams, editors ...
func (i *Impl) Create(ctx context.Context, req api.UserCreateReq, editors ...api.RequestEditorFn) (*api.UserCreateRsp, error) {
res, err := i.client.UserCreateWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -65,7 +68,7 @@ func (i *Impl) Create(ctx context.Context, req api.UserCreateReq, editors ...api
func (i *Impl) Update(ctx context.Context, userID common.UserID, req api.UserUpdateReq, editors ...api.RequestEditorFn) (*api.UserUpdateRsp, error) {
res, err := i.client.UserUpdateWithResponse(ctx, userID, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -79,7 +82,21 @@ func (i *Impl) Update(ctx context.Context, userID common.UserID, req api.UserUpd
func (i *Impl) Get(ctx context.Context, userID common.UserID, params *api.UserGetParams, editors ...api.RequestEditorFn) (*api.UserGetRsp, error) {
res, err := i.client.UserGetWithResponse(ctx, userID, params, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
+ }
+
+ if res.JSONDefault != nil {
+ return nil, servererror.New(res.JSONDefault)
+ }
+
+ return res.JSON200, nil
+}
+
+// Delete deletes a user by ID
+func (i *Impl) Delete(ctx context.Context, userID common.UserID, req api.UserDeleteReq, editors ...api.RequestEditorFn) (*common.GenericRsp, error) {
+ res, err := i.client.UserDeleteWithResponse(ctx, userID, req, editors...)
+ if err != nil {
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
diff --git a/pkg/sdk/validation/validation.go b/internal/services/validation/validation.go
similarity index 85%
rename from pkg/sdk/validation/validation.go
rename to internal/services/validation/validation.go
index d2e24da..9c5e887 100644
--- a/pkg/sdk/validation/validation.go
+++ b/internal/services/validation/validation.go
@@ -3,9 +3,11 @@ package validation
import (
"context"
- "github.com/corbado/corbado-go/pkg/sdk/assert"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
+ "github.com/pkg/errors"
+
+ "github.com/corbado/corbado-go/internal/assert"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
)
type Validation interface {
@@ -34,7 +36,7 @@ func New(client *api.ClientWithResponses) (*Impl, error) {
func (i *Impl) ValidateEmail(ctx context.Context, req api.ValidateEmailReq, editors ...api.RequestEditorFn) (*api.ValidateEmailRsp, error) {
res, err := i.client.ValidateEmailWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
@@ -48,7 +50,7 @@ func (i *Impl) ValidateEmail(ctx context.Context, req api.ValidateEmailReq, edit
func (i *Impl) ValidatePhoneNumber(ctx context.Context, req api.ValidatePhoneNumberReq, editors ...api.RequestEditorFn) (*api.ValidatePhoneNumberRsp, error) {
res, err := i.client.ValidatePhoneNumberWithResponse(ctx, req, editors...)
if err != nil {
- return nil, err
+ return nil, errors.WithStack(err)
}
if res.JSONDefault != nil {
diff --git a/pkg/sdk/entity/claims.go b/pkg/entities/claims.go
similarity index 94%
rename from pkg/sdk/entity/claims.go
rename to pkg/entities/claims.go
index 36edd09..1557155 100644
--- a/pkg/sdk/entity/claims.go
+++ b/pkg/entities/claims.go
@@ -1,4 +1,4 @@
-package entity
+package entities
import "github.com/golang-jwt/jwt/v4"
diff --git a/pkg/sdk/entity/user.go b/pkg/entities/user.go
similarity index 93%
rename from pkg/sdk/entity/user.go
rename to pkg/entities/user.go
index 8a88df5..2f420e9 100644
--- a/pkg/sdk/entity/user.go
+++ b/pkg/entities/user.go
@@ -1,4 +1,4 @@
-package entity
+package entities
type User struct {
Authenticated bool
diff --git a/pkg/sdk/entity/api/api.gen.go b/pkg/generated/api/api.gen.go
similarity index 99%
rename from pkg/sdk/entity/api/api.gen.go
rename to pkg/generated/api/api.gen.go
index 8b88167..3715222 100644
--- a/pkg/sdk/entity/api/api.gen.go
+++ b/pkg/generated/api/api.gen.go
@@ -13,8 +13,9 @@ import (
"net/url"
"strings"
- externalRef0 "github.com/corbado/corbado-go/pkg/sdk/entity/common"
"github.com/oapi-codegen/runtime"
+
+ externalRef0 "github.com/corbado/corbado-go/pkg/generated/common"
)
const (
@@ -358,8 +359,8 @@ type AndroidAppConfigItem struct {
type AndroidAppConfigListRsp struct {
// HttpStatusCode HTTP status code of operation
HttpStatusCode int32 `json:"httpStatusCode"`
- Message string `json:"message"`
- Paging externalRef0.Paging `json:"paging"`
+ Message string `json:"message"`
+ Paging externalRef0.Paging `json:"paging"`
// RequestData Data about the request itself, can be used for debugging
RequestData externalRef0.RequestData `json:"requestData"`
@@ -829,9 +830,9 @@ type EmailLinksValidateReq struct {
// EmailTemplateCreateReq defines model for emailTemplateCreateReq.
type EmailTemplateCreateReq struct {
- Action *string `json:"action,omitempty"`
- ClientInfo *externalRef0.ClientInfo `json:"clientInfo,omitempty"`
- HtmlColorBackgroundInner string `json:"htmlColorBackgroundInner"`
+ Action *string `json:"action,omitempty"`
+ ClientInfo *externalRef0.ClientInfo `json:"clientInfo,omitempty"`
+ HtmlColorBackgroundInner string `json:"htmlColorBackgroundInner"`
HtmlColorBackgroundOuter string `json:"htmlColorBackgroundOuter"`
HtmlColorButton string `json:"htmlColorButton"`
HtmlColorButtonFont string `json:"htmlColorButtonFont"`
@@ -839,15 +840,15 @@ type EmailTemplateCreateReq struct {
HtmlTextBody string `json:"htmlTextBody"`
HtmlTextButton string `json:"htmlTextButton"`
HtmlTextTitle string `json:"htmlTextTitle"`
- IsDefault bool `json:"isDefault"`
- Lang EmailTemplateCreateReqLang `json:"lang"`
- Name string `json:"name"`
+ IsDefault bool `json:"isDefault"`
+ Lang EmailTemplateCreateReqLang `json:"lang"`
+ Name string `json:"name"`
PlainTextBody string `json:"plainTextBody"`
// RequestID Unique ID of request, you can provide your own while making the request, if not the ID will be randomly generated on server side
- RequestID *externalRef0.RequestID `json:"requestID,omitempty"`
- Subject string `json:"subject"`
- Type EmailTemplateCreateReqType `json:"type"`
+ RequestID *externalRef0.RequestID `json:"requestID,omitempty"`
+ Subject string `json:"subject"`
+ Type EmailTemplateCreateReqType `json:"type"`
}
// EmailTemplateCreateReqLang defines model for EmailTemplateCreateReq.Lang.
@@ -952,8 +953,8 @@ type IOSAppConfigItem struct {
type IOSAppConfigListRsp struct {
// HttpStatusCode HTTP status code of operation
HttpStatusCode int32 `json:"httpStatusCode"`
- Message string `json:"message"`
- Paging externalRef0.Paging `json:"paging"`
+ Message string `json:"message"`
+ Paging externalRef0.Paging `json:"paging"`
// RequestData Data about the request itself, can be used for debugging
RequestData externalRef0.RequestData `json:"requestData"`
@@ -1149,28 +1150,28 @@ type ProjectConfig struct {
AllowUserRegistration bool `json:"allowUserRegistration"`
// AppType Application type
- AppType externalRef0.AppType `json:"appType"`
- ApplicationUrl string `json:"applicationUrl"`
+ AppType externalRef0.AppType `json:"appType"`
+ ApplicationUrl string `json:"applicationUrl"`
AuthSuccessRedirectUrl string `json:"authSuccessRedirectUrl"`
AutoDetectLanguage bool `json:"autoDetectLanguage"`
- BackendAPIUrl string `json:"backendAPIUrl"`
- BackendLanguage ProjectConfigBackendLanguage `json:"backendLanguage"`
- CliSecret string `json:"cliSecret"`
+ BackendAPIUrl string `json:"backendAPIUrl"`
+ BackendLanguage ProjectConfigBackendLanguage `json:"backendLanguage"`
+ CliSecret string `json:"cliSecret"`
// Created Timestamp of when the entity was created in yyyy-MM-dd'T'HH:mm:ss format
- Created externalRef0.Created `json:"created"`
- Domain string `json:"domain"`
+ Created externalRef0.Created `json:"created"`
+ Domain string `json:"domain"`
DoubleOptIn bool `json:"doubleOptIn"`
- EmailFrom string `json:"emailFrom"`
- Environment ProjectConfigEnvironment `json:"environment"`
- ExternalApplicationPassword string `json:"externalApplicationPassword"`
+ EmailFrom string `json:"emailFrom"`
+ Environment ProjectConfigEnvironment `json:"environment"`
+ ExternalApplicationPassword string `json:"externalApplicationPassword"`
ExternalApplicationProtocolVersion string `json:"externalApplicationProtocolVersion"`
ExternalApplicationUsername string `json:"externalApplicationUsername"`
ExternalName string `json:"externalName"`
FallbackLanguage string `json:"fallbackLanguage"`
- FrontendAPIUrl string `json:"frontendAPIUrl"`
- FrontendFramework ProjectConfigFrontendFramework `json:"frontendFramework"`
- HasExistingUsers bool `json:"hasExistingUsers"`
+ FrontendAPIUrl string `json:"frontendAPIUrl"`
+ FrontendFramework ProjectConfigFrontendFramework `json:"frontendFramework"`
+ HasExistingUsers bool `json:"hasExistingUsers"`
HasGeneratedSession bool `json:"hasGeneratedSession"`
HasStartedUsingPasskeys bool `json:"hasStartedUsingPasskeys"`
HasStartedUsingSessions bool `json:"hasStartedUsingSessions"`
@@ -1178,17 +1179,17 @@ type ProjectConfig struct {
IntegrationModeAPI bool `json:"integrationModeAPI"`
IntegrationModeHosted bool `json:"integrationModeHosted"`
IntegrationModeWebComponent bool `json:"integrationModeWebComponent"`
- LegacyAuthMethodsUrl string `json:"legacyAuthMethodsUrl"`
- LoginFlow ProjectConfigLoginFlow `json:"loginFlow"`
- LoginFlowOptions map[string]interface{} `json:"loginFlowOptions"`
- PasskeyAppendInterval ProjectConfigPasskeyAppendInterval `json:"passkeyAppendInterval"`
- PasswordResetUrl string `json:"passwordResetUrl"`
+ LegacyAuthMethodsUrl string `json:"legacyAuthMethodsUrl"`
+ LoginFlow ProjectConfigLoginFlow `json:"loginFlow"`
+ LoginFlowOptions map[string]interface{} `json:"loginFlowOptions"`
+ PasskeyAppendInterval ProjectConfigPasskeyAppendInterval `json:"passkeyAppendInterval"`
+ PasswordResetUrl string `json:"passwordResetUrl"`
PasswordVerifyUrl string `json:"passwordVerifyUrl"`
ProductKey string `json:"productKey"`
// ProjectID ID of project
- ProjectID externalRef0.ProjectID `json:"projectID"`
- SignupFlow ProjectConfigSignupFlow `json:"signupFlow"`
+ ProjectID externalRef0.ProjectID `json:"projectID"`
+ SignupFlow ProjectConfigSignupFlow `json:"signupFlow"`
SignupFlowOptions map[string]interface{} `json:"signupFlowOptions"`
SmsFrom string `json:"smsFrom"`
SmtpHost string `json:"smtpHost"`
@@ -1200,8 +1201,8 @@ type ProjectConfig struct {
SupportEmail string `json:"supportEmail"`
// Updated Timestamp of when the entity was last updated in yyyy-MM-dd'T'HH:mm:ss format
- Updated externalRef0.Updated `json:"updated"`
- UseCli bool `json:"useCli"`
+ Updated externalRef0.Updated `json:"updated"`
+ UseCli bool `json:"useCli"`
UserFullNameRequired bool `json:"userFullNameRequired"`
WebComponentDebug bool `json:"webComponentDebug"`
WebauthnRPID string `json:"webauthnRPID"`
@@ -1427,8 +1428,8 @@ type ProjectSecretItem struct {
type ProjectSecretListRsp struct {
// HttpStatusCode HTTP status code of operation
HttpStatusCode int32 `json:"httpStatusCode"`
- Message string `json:"message"`
- Paging externalRef0.Paging `json:"paging"`
+ Message string `json:"message"`
+ Paging externalRef0.Paging `json:"paging"`
// RequestData Data about the request itself, can be used for debugging
RequestData externalRef0.RequestData `json:"requestData"`
@@ -1534,18 +1535,18 @@ type SessionConfig struct {
AppType externalRef0.AppType `json:"appType"`
// Created Timestamp of when the entity was created in yyyy-MM-dd'T'HH:mm:ss format
- Created externalRef0.Created `json:"created"`
- JwtAudience string `json:"jwtAudience"`
+ Created externalRef0.Created `json:"created"`
+ JwtAudience string `json:"jwtAudience"`
LongInactivityUnit SessionConfigLongInactivityUnit `json:"longInactivityUnit"`
LongInactivityValue int `json:"longInactivityValue"`
LongLifetimeUnit SessionConfigLongLifetimeUnit `json:"longLifetimeUnit"`
LongLifetimeValue int `json:"longLifetimeValue"`
// ProjectID ID of project
- ProjectID externalRef0.ProjectID `json:"projectID"`
- ShortCookieDomain string `json:"shortCookieDomain"`
- ShortCookieSameSite SessionConfigShortCookieSameSite `json:"shortCookieSameSite"`
- ShortCookieSecure bool `json:"shortCookieSecure"`
+ ProjectID externalRef0.ProjectID `json:"projectID"`
+ ShortCookieDomain string `json:"shortCookieDomain"`
+ ShortCookieSameSite SessionConfigShortCookieSameSite `json:"shortCookieSameSite"`
+ ShortCookieSecure bool `json:"shortCookieSecure"`
ShortLifetimeMinutes int `json:"shortLifetimeMinutes"`
// Updated Timestamp of when the entity was last updated in yyyy-MM-dd'T'HH:mm:ss format
@@ -1581,16 +1582,16 @@ type SessionConfigUpdateReq struct {
Active *bool `json:"active,omitempty"`
// AppType Application type
- AppType externalRef0.AppType `json:"appType"`
- ClientInfo *externalRef0.ClientInfo `json:"clientInfo,omitempty"`
- LongInactivityUnit *SessionConfigUpdateReqLongInactivityUnit `json:"longInactivityUnit,omitempty"`
+ AppType externalRef0.AppType `json:"appType"`
+ ClientInfo *externalRef0.ClientInfo `json:"clientInfo,omitempty"`
+ LongInactivityUnit *SessionConfigUpdateReqLongInactivityUnit `json:"longInactivityUnit,omitempty"`
LongInactivityValue *int `json:"longInactivityValue,omitempty"`
LongLifetimeUnit *SessionConfigUpdateReqLongLifetimeUnit `json:"longLifetimeUnit,omitempty"`
LongLifetimeValue *int `json:"longLifetimeValue,omitempty"`
// RequestID Unique ID of request, you can provide your own while making the request, if not the ID will be randomly generated on server side
- RequestID *externalRef0.RequestID `json:"requestID,omitempty"`
- ShortCookieDomain *string `json:"shortCookieDomain,omitempty"`
+ RequestID *externalRef0.RequestID `json:"requestID,omitempty"`
+ ShortCookieDomain *string `json:"shortCookieDomain,omitempty"`
ShortCookieSameSite *SessionConfigUpdateReqShortCookieSameSite `json:"shortCookieSameSite,omitempty"`
ShortCookieSecure *bool `json:"shortCookieSecure,omitempty"`
ShortLifetimeMinutes *int `json:"shortLifetimeMinutes,omitempty"`
@@ -1737,8 +1738,8 @@ type SmsTemplateCreateReq struct {
Name string `json:"name"`
// RequestID Unique ID of request, you can provide your own while making the request, if not the ID will be randomly generated on server side
- RequestID *externalRef0.RequestID `json:"requestID,omitempty"`
- TextPlain string `json:"textPlain"`
+ RequestID *externalRef0.RequestID `json:"requestID,omitempty"`
+ TextPlain string `json:"textPlain"`
Type SmsTemplateCreateReqType `json:"type"`
}
@@ -1901,9 +1902,9 @@ type TrackingEnumsGetRsp struct {
type TrackingOSDetailedStats struct {
Cnt int `json:"cnt"`
ConditionalUi int `json:"conditional_ui"`
- OsName string `json:"osName"`
- OsPlatform TrackingOSDetailedStatsOsPlatform `json:"osPlatform"`
- OsVersion string `json:"osVersion"`
+ OsName string `json:"osName"`
+ OsPlatform TrackingOSDetailedStatsOsPlatform `json:"osPlatform"`
+ OsVersion string `json:"osVersion"`
Platform int `json:"platform"`
TimePoint string `json:"timePoint"`
Webauthn int `json:"webauthn"`
@@ -1972,8 +1973,8 @@ type TrackingRawListRow struct {
type TrackingRawListRsp struct {
// HttpStatusCode HTTP status code of operation
HttpStatusCode int32 `json:"httpStatusCode"`
- Message string `json:"message"`
- Paging externalRef0.Paging `json:"paging"`
+ Message string `json:"message"`
+ Paging externalRef0.Paging `json:"paging"`
// RequestData Data about the request itself, can be used for debugging
RequestData externalRef0.RequestData `json:"requestData"`
@@ -2166,8 +2167,8 @@ type UserDeviceListRsp struct {
// HttpStatusCode HTTP status code of operation
HttpStatusCode int32 `json:"httpStatusCode"`
- Message string `json:"message"`
- Paging externalRef0.Paging `json:"paging"`
+ Message string `json:"message"`
+ Paging externalRef0.Paging `json:"paging"`
// RequestData Data about the request itself, can be used for debugging
RequestData externalRef0.RequestData `json:"requestData"`
@@ -2663,8 +2664,8 @@ type WebAuthnCredentialItemRspTransport string
type WebAuthnCredentialListRsp struct {
// HttpStatusCode HTTP status code of operation
HttpStatusCode int32 `json:"httpStatusCode"`
- Message string `json:"message"`
- Paging externalRef0.Paging `json:"paging"`
+ Message string `json:"message"`
+ Paging externalRef0.Paging `json:"paging"`
// RequestData Data about the request itself, can be used for debugging
RequestData externalRef0.RequestData `json:"requestData"`
@@ -2923,8 +2924,8 @@ type WebauthnSettingItem struct {
type WebauthnSettingListRsp struct {
// HttpStatusCode HTTP status code of operation
HttpStatusCode int32 `json:"httpStatusCode"`
- Message string `json:"message"`
- Paging externalRef0.Paging `json:"paging"`
+ Message string `json:"message"`
+ Paging externalRef0.Paging `json:"paging"`
// RequestData Data about the request itself, can be used for debugging
RequestData externalRef0.RequestData `json:"requestData"`
diff --git a/pkg/sdk/entity/common/common.gen.go b/pkg/generated/common/common.gen.go
similarity index 100%
rename from pkg/sdk/entity/common/common.gen.go
rename to pkg/generated/common/common.gen.go
diff --git a/pkg/sdk/assert/assert.go b/pkg/sdk/assert/assert.go
deleted file mode 100644
index d66d93b..0000000
--- a/pkg/sdk/assert/assert.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package assert
-
-import (
- "fmt"
- "reflect"
-
- "github.com/pkg/errors"
-)
-
-// NotNil checks given value if it is not nil
-func NotNil(values ...any) error {
- for i, value := range values {
- if value == nil {
- return errors.WithStack(fmt.Errorf("assert failed: given value at index %d is nil", i))
- }
-
- switch reflect.TypeOf(value).Kind() {
- case reflect.Ptr, reflect.Map, reflect.Array, reflect.Chan, reflect.Slice, reflect.Func:
- if reflect.ValueOf(value).IsNil() {
- return errors.WithStack(fmt.Errorf("assert failed: given value at index %d is nil", i))
- }
- }
- }
-
- return nil
-}
-
-// StringLength checks a string for the given min and max length
-func StringLength(value string, minLength int, maxLength int, allowedValues *[]string /* can be nil */) error {
- if minLength != -1 && maxLength != -1 && minLength > maxLength {
- return errors.Errorf("assert misuse: minLength should be smaller than maxLength (minLength: %d, maxLength: %d)", minLength, maxLength)
- }
-
- lenString := len(value)
- if minLength != -1 && lenString < minLength {
- return errors.Errorf("assert failed: given value '%s' is too short (%d < %d)", value, lenString, minLength)
- }
-
- if maxLength != -1 && lenString > maxLength {
- return errors.Errorf("assert failed: given value '%s' is too long (%d > %d)", value, lenString, minLength)
- }
-
- if allowedValues != nil {
- found := false
- for _, allowedValue := range *allowedValues {
- if allowedValue == value {
- found = true
- break
- }
- }
-
- if !found {
- return errors.Errorf("assert failed: given value '%s' is not in allowed values (%s)", value, *allowedValues)
- }
- }
-
- return nil
-}
-
-// StringNotEmpty checks if given string is not empty
-func StringNotEmpty(value string) error {
- return StringLength(value, 1, -1, nil)
-}
diff --git a/pkg/sdk/servererror/servererror.go b/pkg/servererror/servererror.go
similarity index 97%
rename from pkg/sdk/servererror/servererror.go
rename to pkg/servererror/servererror.go
index 98650e1..1ca2848 100644
--- a/pkg/sdk/servererror/servererror.go
+++ b/pkg/servererror/servererror.go
@@ -4,7 +4,7 @@ import (
"fmt"
"strings"
- "github.com/corbado/corbado-go/pkg/sdk/entity/common"
+ "github.com/corbado/corbado-go/pkg/generated/common"
)
type ValidationErrors = []struct {
diff --git a/pkg/stdlib/sdk_helpers.go b/pkg/stdlib/sdk_helpers.go
index eee0f43..3fe1494 100644
--- a/pkg/stdlib/sdk_helpers.go
+++ b/pkg/stdlib/sdk_helpers.go
@@ -4,18 +4,20 @@ import (
"net/http"
"strings"
- "github.com/corbado/corbado-go/pkg/sdk/assert"
- "github.com/corbado/corbado-go/pkg/sdk/config"
- "github.com/corbado/corbado-go/pkg/sdk/entity/common"
- "github.com/corbado/corbado-go/pkg/sdk/util"
"github.com/pkg/errors"
+
+ "github.com/corbado/corbado-go/internal/assert"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/common"
+ "github.com/corbado/corbado-go/pkg/util"
)
type SDKHelpers struct {
- config *config.Config
+ config *corbado.Config
}
-func NewSDKHelpers(config *config.Config) (*SDKHelpers, error) {
+func NewSDKHelpers(config *corbado.Config) (*SDKHelpers, error) {
if err := assert.NotNil(config); err != nil {
return nil, err
}
@@ -65,6 +67,10 @@ func (s *SDKHelpers) getShortSessionValueFromAuthHeader(req *http.Request) (stri
}
authHeader := req.Header.Get("Authorization")
+ if len(authHeader) < 8 {
+ return "", nil
+ }
+
if !strings.HasPrefix(authHeader, "Bearer ") {
return "", nil
}
diff --git a/pkg/sdk/util/util.go b/pkg/util/util.go
similarity index 78%
rename from pkg/sdk/util/util.go
rename to pkg/util/util.go
index 75643e8..a1004d5 100644
--- a/pkg/sdk/util/util.go
+++ b/pkg/util/util.go
@@ -1,7 +1,7 @@
package util
import (
- "github.com/corbado/corbado-go/pkg/sdk/entity/common"
+ "github.com/corbado/corbado-go/pkg/generated/common"
)
// Ptr returns a pointer to provided value
@@ -18,6 +18,7 @@ func RequestID(requestID string) *common.RequestID {
return nil
}
+// ClientInfo returns client info based on provided user agent and remote address
func ClientInfo(userAgent string, remoteAddress string) *common.ClientInfo {
if userAgent == "" && remoteAddress == "" {
return nil
diff --git a/sdk.go b/sdk.go
index 6d89eee..d43eec5 100644
--- a/sdk.go
+++ b/sdk.go
@@ -1,33 +1,36 @@
package corbado
import (
+ "fmt"
"net/http"
- "github.com/corbado/corbado-go/pkg/sdk/assert"
- "github.com/corbado/corbado-go/pkg/sdk/authtoken"
- "github.com/corbado/corbado-go/pkg/sdk/config"
- "github.com/corbado/corbado-go/pkg/sdk/emailcode"
- "github.com/corbado/corbado-go/pkg/sdk/emaillink"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/passkey"
- "github.com/corbado/corbado-go/pkg/sdk/project"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
- "github.com/corbado/corbado-go/pkg/sdk/session"
- "github.com/corbado/corbado-go/pkg/sdk/template"
- "github.com/corbado/corbado-go/pkg/sdk/user"
- "github.com/corbado/corbado-go/pkg/sdk/validation"
"github.com/pkg/errors"
+
+ "github.com/corbado/corbado-go/internal/assert"
+ "github.com/corbado/corbado-go/internal/services/authtoken"
+ "github.com/corbado/corbado-go/internal/services/emailmagiclink"
+ "github.com/corbado/corbado-go/internal/services/emailotp"
+ "github.com/corbado/corbado-go/internal/services/passkey"
+ "github.com/corbado/corbado-go/internal/services/project"
+ "github.com/corbado/corbado-go/internal/services/session"
+ "github.com/corbado/corbado-go/internal/services/smsotp"
+ "github.com/corbado/corbado-go/internal/services/template"
+ "github.com/corbado/corbado-go/internal/services/user"
+ "github.com/corbado/corbado-go/internal/services/validation"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
)
-const Version = "v0.6.0"
+const Version = "1.0.0"
type SDK interface {
AuthTokens() authtoken.AuthToken
- EmailCodes() emailcode.EmailCode
- EmailLinks() emaillink.EmailLink
+ EmailMagicLinks() emailmagiclink.EmailMagicLink
+ EmailOTPs() emailotp.EmailOTP
Passkeys() passkey.Passkey
Projects() project.Project
Sessions() session.Session
+ SmsOTPs() smsotp.SmsOTP
Templates() template.Template
Users() user.User
Validations() validation.Validation
@@ -37,25 +40,30 @@ type Impl struct {
client *api.ClientWithResponses
HTTPClient *http.Client
- authTokens authtoken.AuthToken
- emailCodes emailcode.EmailCode
- emailLinks emaillink.EmailLink
- passkeys passkey.Passkey
- projects project.Project
- sessions session.Session
- templates template.Template
- validation validation.Validation
- users user.User
+ authTokens authtoken.AuthToken
+ emailMagicLinks emailmagiclink.EmailMagicLink
+ emailOTPs emailotp.EmailOTP
+ passkeys passkey.Passkey
+ projects project.Project
+ sessions session.Session
+ smsOTPs smsotp.SmsOTP
+ templates template.Template
+ users user.User
+ validations validation.Validation
}
var _ SDK = &Impl{}
// NewSDK returns new SDK
-func NewSDK(config *config.Config) (*Impl, error) {
+func NewSDK(config *Config) (*Impl, error) {
if err := assert.NotNil(config); err != nil {
return nil, err
}
+ if err := config.validate(); err != nil {
+ return nil, err
+ }
+
client, err := newClient(config)
if err != nil {
return nil, err
@@ -67,12 +75,12 @@ func NewSDK(config *config.Config) (*Impl, error) {
return nil, err
}
- emailCodes, err := emailcode.New(client)
+ emailMagicLinks, err := emailmagiclink.New(client)
if err != nil {
return nil, err
}
- emailLinks, err := emaillink.New(client)
+ emailOTPs, err := emailotp.New(client)
if err != nil {
return nil, err
}
@@ -87,7 +95,21 @@ func NewSDK(config *config.Config) (*Impl, error) {
return nil, err
}
- sessions, err := session.New(client, config)
+ sessionConfig := &session.Config{
+ ProjectID: config.ProjectID,
+ JWTIssuer: config.FrontendAPI,
+ JwksURI: fmt.Sprintf("%s/.well-known/jwks", config.FrontendAPI),
+ JWKSRefreshInterval: config.JWKSRefreshInterval,
+ JWKSRefreshRateLimit: config.JWKSRefreshRateLimit,
+ JWKSRefreshTimeout: config.JWKSRefreshTimeout,
+ }
+
+ sessions, err := session.New(client, sessionConfig)
+ if err != nil {
+ return nil, err
+ }
+
+ smsOTPs, err := smsotp.New(client)
if err != nil {
return nil, err
}
@@ -102,7 +124,7 @@ func NewSDK(config *config.Config) (*Impl, error) {
return nil, err
}
- validation, err := validation.New(client)
+ validations, err := validation.New(client)
if err != nil {
return nil, err
}
@@ -113,17 +135,18 @@ func NewSDK(config *config.Config) (*Impl, error) {
}
return &Impl{
- client: client,
- authTokens: authTokens,
- emailCodes: emailCodes,
- emailLinks: emailLinks,
- passkeys: passkeys,
- projects: projects,
- sessions: sessions,
- templates: templates,
- users: users,
- validation: validation,
- HTTPClient: httpClient,
+ client: client,
+ authTokens: authTokens,
+ emailMagicLinks: emailMagicLinks,
+ emailOTPs: emailOTPs,
+ passkeys: passkeys,
+ projects: projects,
+ sessions: sessions,
+ smsOTPs: smsOTPs,
+ templates: templates,
+ users: users,
+ validations: validations,
+ HTTPClient: httpClient,
}, nil
}
@@ -132,19 +155,14 @@ func (i *Impl) AuthTokens() authtoken.AuthToken {
return i.authTokens
}
-// EmailCodes returns email codes client
-func (i *Impl) EmailCodes() emailcode.EmailCode {
- return i.emailCodes
-}
-
-// EmailLinks returns email links client
-func (i *Impl) EmailLinks() emaillink.EmailLink {
- return i.emailLinks
+// EmailMagicLinks returns email magic links client
+func (i *Impl) EmailMagicLinks() emailmagiclink.EmailMagicLink {
+ return i.emailMagicLinks
}
-// Validations returns validation client
-func (i *Impl) Validations() validation.Validation {
- return i.validation
+// EmailOTPs returns email OTPs client
+func (i *Impl) EmailOTPs() emailotp.EmailOTP {
+ return i.emailOTPs
}
// Passkeys returns passkeys client
@@ -162,6 +180,11 @@ func (i *Impl) Sessions() session.Session {
return i.sessions
}
+// SmsOTPs returns sms OTPs client
+func (i *Impl) SmsOTPs() smsotp.SmsOTP {
+ return i.smsOTPs
+}
+
// Templates returns templates client
func (i *Impl) Templates() template.Template {
return i.templates
@@ -172,6 +195,11 @@ func (i *Impl) Users() user.User {
return i.users
}
+// Validations returns validation client
+func (i *Impl) Validations() validation.Validation {
+ return i.validations
+}
+
// IsServerError checks if given error is a ServerError
func IsServerError(err error) bool {
var serverError *servererror.ServerError
@@ -190,15 +218,3 @@ func AsServerError(err error) *servererror.ServerError {
return serverError
}
-
-// NewConfig returns new config with sane defaults
-// this is a convenience function for config.NewConfig to avoid import cycles
-func NewConfig(projectID string, apiSecret string) (*config.Config, error) {
- return config.NewConfig(projectID, apiSecret)
-}
-
-// MustNewConfig returns new config and panics if projectID or apiSecret are not specified/empty
-// this is a convenience function for config.NewConfig to avoid import cycles
-func MustNewConfig(projectID string, apiSecret string) *config.Config {
- return config.MustNewConfig(projectID, apiSecret)
-}
diff --git a/tests/integration/authtoken/auth_token_validate_test.go b/tests/integration/authtoken/auth_token_validate_test.go
index 1e89d09..15f2b47 100644
--- a/tests/integration/authtoken/auth_token_validate_test.go
+++ b/tests/integration/authtoken/auth_token_validate_test.go
@@ -8,13 +8,14 @@ import (
"strings"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
- "github.com/corbado/corbado-go/pkg/sdk/util"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/pkg/util"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestAuthTokenValidate_ValidationError(t *testing.T) {
@@ -25,9 +26,9 @@ func TestAuthTokenValidate_ValidationError(t *testing.T) {
require.Nil(t, rsp)
require.NotNil(t, err)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, "token: the length must be exactly 64", servererror.GetValidationMessage(serverErr.Validation))
}
@@ -39,9 +40,9 @@ func TestAuthTokenValidate_NotExists(t *testing.T) {
require.Nil(t, rsp)
require.NotNil(t, err)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, int32(http.StatusNotFound), serverErr.HTTPStatusCode)
require.NotNil(t, serverErr.Details)
assert.Equal(t, "Session doesn't exist", *serverErr.Details)
diff --git a/tests/integration/emailcode/email_code_send_test.go b/tests/integration/emailcode/email_code_send_test.go
deleted file mode 100644
index cc2f370..0000000
--- a/tests/integration/emailcode/email_code_send_test.go
+++ /dev/null
@@ -1,27 +0,0 @@
-//go:build integration
-
-package emailcode_test
-
-import (
- "context"
- "testing"
-
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/util"
- "github.com/corbado/corbado-go/tests/integration"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-func TestEmailCodeSend(t *testing.T) {
- rsp, err := integration.SDK(t).EmailCodes().Send(context.TODO(), api.EmailCodeSendReq{
- Email: integration.CreateRandomTestEmail(t),
- TemplateName: util.Ptr("default"),
- Create: true,
- AdditionalPayload: util.Ptr("{}"),
- ClientInfo: util.ClientInfo("foobar", "127.0.0.1"),
- })
-
- require.NoError(t, err)
- assert.NotEmpty(t, rsp.Data.EmailCodeID)
-}
diff --git a/tests/integration/emaillink/email_link_send_test.go b/tests/integration/emailmagiclink/email_magiclink_send_test.go
similarity index 71%
rename from tests/integration/emaillink/email_link_send_test.go
rename to tests/integration/emailmagiclink/email_magiclink_send_test.go
index c7af943..1200e61 100644
--- a/tests/integration/emaillink/email_link_send_test.go
+++ b/tests/integration/emailmagiclink/email_magiclink_send_test.go
@@ -6,15 +6,16 @@ import (
"context"
"testing"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/util"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/util"
+ "github.com/corbado/corbado-go/tests/integration"
)
-func TestEmailLinkSend(t *testing.T) {
- rsp, err := integration.SDK(t).EmailLinks().Send(context.TODO(), api.EmailLinkSendReq{
+func TestEmailMagicLinkSend(t *testing.T) {
+ rsp, err := integration.SDK(t).EmailMagicLinks().Send(context.TODO(), api.EmailLinkSendReq{
Email: integration.CreateRandomTestEmail(t),
Redirect: "https://some.site.com/authenticate",
TemplateName: util.Ptr("default"),
diff --git a/tests/integration/emailotp/email_otp_send_test.go b/tests/integration/emailotp/email_otp_send_test.go
new file mode 100644
index 0000000..b2636c6
--- /dev/null
+++ b/tests/integration/emailotp/email_otp_send_test.go
@@ -0,0 +1,46 @@
+//go:build integration
+
+package emailotp_test
+
+import (
+ "context"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/pkg/util"
+ "github.com/corbado/corbado-go/tests/integration"
+)
+
+func TestEmailOTPSend_ValidationError(t *testing.T) {
+ _, err := integration.SDK(t).EmailOTPs().Send(context.TODO(), api.EmailCodeSendReq{
+ Email: "",
+ TemplateName: util.Ptr("default"),
+ Create: true,
+ AdditionalPayload: util.Ptr("{}"),
+ ClientInfo: util.ClientInfo("foobar", "127.0.0.1"),
+ })
+
+ require.Error(t, err)
+
+ serverErr := corbado.AsServerError(err)
+ require.NotNil(t, serverErr)
+ assert.Contains(t, servererror.GetValidationMessage(serverErr.Validation), "email: cannot be blank")
+}
+
+func TestEmailOTPSend_Success(t *testing.T) {
+ rsp, err := integration.SDK(t).EmailOTPs().Send(context.TODO(), api.EmailCodeSendReq{
+ Email: integration.CreateRandomTestEmail(t),
+ TemplateName: util.Ptr("default"),
+ Create: true,
+ AdditionalPayload: util.Ptr("{}"),
+ ClientInfo: util.ClientInfo("foobar", "127.0.0.1"),
+ })
+
+ require.NoError(t, err)
+ assert.NotEmpty(t, rsp.Data.EmailCodeID)
+}
diff --git a/tests/integration/emailotp/email_otp_validate_test.go b/tests/integration/emailotp/email_otp_validate_test.go
new file mode 100644
index 0000000..b1e1981
--- /dev/null
+++ b/tests/integration/emailotp/email_otp_validate_test.go
@@ -0,0 +1,72 @@
+//go:build integration
+
+package emailotp_test
+
+import (
+ "context"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/pkg/util"
+ "github.com/corbado/corbado-go/tests/integration"
+)
+
+func TestEmailOTPValidate_ValidationErrorEmptyCode(t *testing.T) {
+ _, err := integration.SDK(t).EmailOTPs().Validate(context.TODO(), "emc-123456789", api.EmailCodeValidateReq{
+ Code: "",
+ })
+
+ require.Error(t, err)
+
+ serverErr := corbado.AsServerError(err)
+ require.NotNil(t, serverErr)
+ assert.Contains(t, servererror.GetValidationMessage(serverErr.Validation), "code: cannot be blank")
+}
+
+func TestEmailOTPValidate_ValidationErrorInvalidCode(t *testing.T) {
+ _, err := integration.SDK(t).EmailOTPs().Validate(context.TODO(), "emc-123456789", api.EmailCodeValidateReq{
+ Code: "1",
+ })
+
+ require.Error(t, err)
+
+ serverErr := corbado.AsServerError(err)
+ require.NotNil(t, serverErr)
+ assert.Contains(t, servererror.GetValidationMessage(serverErr.Validation), "code: the length must be exactly 6")
+}
+
+func TestEmailOTPValidate_ValidationErrorInvalidID(t *testing.T) {
+ _, err := integration.SDK(t).EmailOTPs().Validate(context.TODO(), "emc-123456789", api.EmailCodeValidateReq{
+ Code: "123456",
+ })
+
+ require.Error(t, err)
+
+ serverErr := corbado.AsServerError(err)
+ require.NotNil(t, serverErr)
+ assert.Equal(t, int32(404), serverErr.HTTPStatusCode)
+}
+
+func TestEmailOTPValidate_Success(t *testing.T) {
+ rsp, err := integration.SDK(t).EmailOTPs().Send(context.TODO(), api.EmailCodeSendReq{
+ Email: integration.CreateRandomTestEmail(t),
+ TemplateName: util.Ptr("default"),
+ Create: true,
+ AdditionalPayload: util.Ptr("{}"),
+ ClientInfo: util.ClientInfo("foobar", "127.0.0.1"),
+ })
+
+ require.NoError(t, err)
+ assert.NotEmpty(t, rsp.Data.EmailCodeID)
+
+ _, err = integration.SDK(t).EmailOTPs().Validate(context.TODO(), rsp.Data.EmailCodeID, api.EmailCodeValidateReq{
+ Code: "150919",
+ })
+
+ require.NoError(t, err)
+}
diff --git a/tests/integration/passkey/webauthn_associate_start_test.go b/tests/integration/passkey/webauthn_associate_start_test.go
index 99c5a8d..0437a56 100644
--- a/tests/integration/passkey/webauthn_associate_start_test.go
+++ b/tests/integration/passkey/webauthn_associate_start_test.go
@@ -6,23 +6,25 @@ import (
"context"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
- "github.com/corbado/corbado-go/pkg/sdk/util"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/pkg/util"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestWebAuthnAssociateStart_ValidationError(t *testing.T) {
rsp, err := integration.SDK(t).Passkeys().AssociateStart(context.TODO(), api.WebAuthnAssociateStartReq{
ClientInfo: util.ClientInfo("foobar", "127.0.0.1"),
})
+
require.Nil(t, rsp)
require.NotNil(t, err)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, "associationToken: cannot be blank", servererror.GetValidationMessage(serverErr.Validation))
}
diff --git a/tests/integration/passkey/webauthn_authenticate_finish_test.go b/tests/integration/passkey/webauthn_authenticate_finish_test.go
index c66662b..d5c5549 100644
--- a/tests/integration/passkey/webauthn_authenticate_finish_test.go
+++ b/tests/integration/passkey/webauthn_authenticate_finish_test.go
@@ -6,23 +6,25 @@ import (
"context"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
- "github.com/corbado/corbado-go/pkg/sdk/util"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/pkg/util"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestWebAuthnAuthenticateFinish_ValidationError(t *testing.T) {
rsp, err := integration.SDK(t).Passkeys().AuthenticateFinish(context.TODO(), api.WebAuthnFinishReq{
ClientInfo: *util.ClientInfo("foobar", "127.0.0.1"),
})
+
require.Nil(t, rsp)
require.NotNil(t, err)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, "publicKeyCredential: cannot be blank", servererror.GetValidationMessage(serverErr.Validation))
}
diff --git a/tests/integration/passkey/webauthn_authenticate_start_test.go b/tests/integration/passkey/webauthn_authenticate_start_test.go
index 3d0e909..61d61ba 100644
--- a/tests/integration/passkey/webauthn_authenticate_start_test.go
+++ b/tests/integration/passkey/webauthn_authenticate_start_test.go
@@ -6,13 +6,14 @@ import (
"context"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
- "github.com/corbado/corbado-go/pkg/sdk/util"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/pkg/util"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestWebAuthnAuthenticateStart_ValidationError(t *testing.T) {
@@ -20,10 +21,11 @@ func TestWebAuthnAuthenticateStart_ValidationError(t *testing.T) {
Username: "",
ClientInfo: *util.ClientInfo("foobar", "127.0.0.1"),
})
+
require.Nil(t, rsp)
require.NotNil(t, err)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, "username: cannot be blank", servererror.GetValidationMessage(serverErr.Validation))
}
diff --git a/tests/integration/passkey/webauthn_credential_delete_test.go b/tests/integration/passkey/webauthn_credential_delete_test.go
index 65056da..d753063 100644
--- a/tests/integration/passkey/webauthn_credential_delete_test.go
+++ b/tests/integration/passkey/webauthn_credential_delete_test.go
@@ -6,20 +6,20 @@ import (
"context"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestWebAuthnCredentialDelete_ValidationError(t *testing.T) {
err := integration.SDK(t).Passkeys().CredentialDelete(context.TODO(), "usr-12345678", "cre-12345678", api.EmptyReq{})
-
require.NotNil(t, err)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, "credentialID: does not exist", servererror.GetValidationMessage(serverErr.Validation))
}
diff --git a/tests/integration/passkey/webauthn_credential_list_test.go b/tests/integration/passkey/webauthn_credential_list_test.go
index 0d9dd80..59bdc21 100644
--- a/tests/integration/passkey/webauthn_credential_list_test.go
+++ b/tests/integration/passkey/webauthn_credential_list_test.go
@@ -6,13 +6,14 @@ import (
"context"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
- "github.com/corbado/corbado-go/pkg/sdk/util"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/pkg/util"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestWebAuthnCredentialList_ValidationError(t *testing.T) {
@@ -22,15 +23,14 @@ func TestWebAuthnCredentialList_ValidationError(t *testing.T) {
require.Nil(t, rsp)
require.NotNil(t, err)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, "sort: Invalid order direction 'bar'", servererror.GetValidationMessage(serverErr.Validation))
}
func TestWebAuthnCredentialList_Success(t *testing.T) {
rsp, err := integration.SDK(t).Passkeys().CredentialList(context.TODO(), nil)
require.NoError(t, err)
-
assert.True(t, len(rsp.Rows) == 0)
}
diff --git a/tests/integration/passkey/webauthn_credential_update_test.go b/tests/integration/passkey/webauthn_credential_update_test.go
index ec425be..3d7e3cd 100644
--- a/tests/integration/passkey/webauthn_credential_update_test.go
+++ b/tests/integration/passkey/webauthn_credential_update_test.go
@@ -6,12 +6,13 @@ import (
"context"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestWebAuthnCredentialUpdate_ValidationError(t *testing.T) {
@@ -21,8 +22,8 @@ func TestWebAuthnCredentialUpdate_ValidationError(t *testing.T) {
require.Nil(t, rsp)
require.NotNil(t, err)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, "credentialID: does not exist", servererror.GetValidationMessage(serverErr.Validation))
}
diff --git a/tests/integration/passkey/webauthn_mediation_start_test.go b/tests/integration/passkey/webauthn_mediation_start_test.go
index e272618..48ccbe5 100644
--- a/tests/integration/passkey/webauthn_mediation_start_test.go
+++ b/tests/integration/passkey/webauthn_mediation_start_test.go
@@ -6,22 +6,23 @@ import (
"context"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
- "github.com/corbado/corbado-go/pkg/sdk/util"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/pkg/util"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestWebAuthnMediationStart_ValidationError(t *testing.T) {
rsp, err := integration.SDK(t).Passkeys().MediationStart(context.TODO(), api.WebAuthnMediationStartReq{})
require.Nil(t, rsp)
require.NotNil(t, err)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Contains(t, servererror.GetValidationMessage(serverErr.Validation), "userAgent: cannot be blank")
}
diff --git a/tests/integration/passkey/webauthn_register_finish_test.go b/tests/integration/passkey/webauthn_register_finish_test.go
index 3c6dd07..9e3cadd 100644
--- a/tests/integration/passkey/webauthn_register_finish_test.go
+++ b/tests/integration/passkey/webauthn_register_finish_test.go
@@ -6,23 +6,25 @@ import (
"context"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
- "github.com/corbado/corbado-go/pkg/sdk/util"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/pkg/util"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestWebAuthnRegisterFinish_ValidationError(t *testing.T) {
rsp, err := integration.SDK(t).Passkeys().RegisterFinish(context.TODO(), api.WebAuthnFinishReq{
ClientInfo: *util.ClientInfo("foobar", "127.0.0.1"),
})
+
require.Nil(t, rsp)
require.NotNil(t, err)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, "publicKeyCredential: cannot be blank", servererror.GetValidationMessage(serverErr.Validation))
}
diff --git a/tests/integration/passkey/webauthn_register_start_test.go b/tests/integration/passkey/webauthn_register_start_test.go
index b677478..b1a7273 100644
--- a/tests/integration/passkey/webauthn_register_start_test.go
+++ b/tests/integration/passkey/webauthn_register_start_test.go
@@ -6,13 +6,14 @@ import (
"context"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
- "github.com/corbado/corbado-go/pkg/sdk/util"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/pkg/util"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestWebAuthnRegisterStart_ValidationError(t *testing.T) {
@@ -20,11 +21,12 @@ func TestWebAuthnRegisterStart_ValidationError(t *testing.T) {
Username: "",
ClientInfo: *util.ClientInfo("foobar", "127.0.0.1"),
})
+
require.Nil(t, rsp)
require.NotNil(t, err)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, "username: cannot be blank", servererror.GetValidationMessage(serverErr.Validation))
}
diff --git a/tests/integration/project/project_config_get_test.go b/tests/integration/project/project_config_get_test.go
index 0d1fd60..ee0aed5 100644
--- a/tests/integration/project/project_config_get_test.go
+++ b/tests/integration/project/project_config_get_test.go
@@ -7,26 +7,26 @@ import (
"net/http"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestProjectConfigGet_AuthError(t *testing.T) {
- config, err := corbado.NewConfig("pro-12345678", "wrongsecret")
+ config, err := corbado.NewConfig("pro-12345678", "corbado1_wrongsecret")
require.NoError(t, err)
- config.BackendAPI = integration.GetBackendAPI(t)
+ config.BackendAPI = integration.GetBackendAPI(t)
sdk, err := corbado.NewSDK(config)
require.NoError(t, err)
rsp, err := sdk.Projects().ConfigGet(context.TODO())
-
require.Nil(t, rsp)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, int32(http.StatusUnauthorized), serverErr.HTTPStatusCode)
assert.Equal(t, "login_error", serverErr.Type)
}
diff --git a/tests/integration/project/project_config_update_test.go b/tests/integration/project/project_config_update_test.go
index dedebc0..e2d65ec 100644
--- a/tests/integration/project/project_config_update_test.go
+++ b/tests/integration/project/project_config_update_test.go
@@ -6,13 +6,14 @@ import (
"context"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
- "github.com/corbado/corbado-go/pkg/sdk/util"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/pkg/util"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestProjectConfigUpdate_ValidationError(t *testing.T) {
@@ -21,9 +22,9 @@ func TestProjectConfigUpdate_ValidationError(t *testing.T) {
})
require.NotNil(t, err)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, "externalName: the length must be between 2 and 255", servererror.GetValidationMessage(serverErr.Validation))
}
diff --git a/tests/integration/project/project_secret_create_test.go b/tests/integration/project/project_secret_create_test.go
index 6d7e1a8..795d991 100644
--- a/tests/integration/project/project_secret_create_test.go
+++ b/tests/integration/project/project_secret_create_test.go
@@ -6,10 +6,11 @@ import (
"context"
"testing"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestProjectSecretCreate_Success(t *testing.T) {
diff --git a/tests/integration/session/session_config_get_test.go b/tests/integration/session/session_config_get_test.go
index 0abc15c..f250526 100644
--- a/tests/integration/session/session_config_get_test.go
+++ b/tests/integration/session/session_config_get_test.go
@@ -7,33 +7,32 @@ import (
"net/http"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestSessionConfigGet_AuthError(t *testing.T) {
- config, err := corbado.NewConfig("pro-12345678", "wrongsecret")
+ config, err := corbado.NewConfig("pro-12345678", "corbado1_wrongsecret")
require.NoError(t, err)
- config.BackendAPI = integration.GetBackendAPI(t)
+ config.BackendAPI = integration.GetBackendAPI(t)
sdk, err := corbado.NewSDK(config)
require.NoError(t, err)
rsp, err := sdk.Sessions().ConfigGet(context.TODO(), nil)
-
require.Nil(t, rsp)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, int32(http.StatusUnauthorized), serverErr.HTTPStatusCode)
assert.Equal(t, "login_error", serverErr.Type)
}
func TestSessionConfigGet_Success(t *testing.T) {
rsp, err := integration.SDK(t).Sessions().ConfigGet(context.TODO(), nil)
-
require.NoError(t, err)
assert.Equal(t, integration.GetProjectID(t), rsp.Data.ProjectID)
}
diff --git a/tests/integration/smsotp/sms_otp_send_test.go b/tests/integration/smsotp/sms_otp_send_test.go
new file mode 100644
index 0000000..2b1833c
--- /dev/null
+++ b/tests/integration/smsotp/sms_otp_send_test.go
@@ -0,0 +1,44 @@
+//go:build integration
+
+package smsotp_test
+
+import (
+ "context"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/pkg/util"
+ "github.com/corbado/corbado-go/tests/integration"
+)
+
+func TestSmsOTPSend_ValidationError(t *testing.T) {
+ _, err := integration.SDK(t).SmsOTPs().Send(context.TODO(), api.SmsCodeSendReq{
+ PhoneNumber: "",
+ TemplateName: util.Ptr("default"),
+ Create: true,
+ ClientInfo: util.ClientInfo("foobar", "127.0.0.1"),
+ })
+
+ require.Error(t, err)
+
+ serverErr := corbado.AsServerError(err)
+ require.NotNil(t, serverErr)
+ assert.Contains(t, servererror.GetValidationMessage(serverErr.Validation), "phoneNumber: cannot be blank")
+}
+
+func TestSmsOTPSend_Success(t *testing.T) {
+ rsp, err := integration.SDK(t).SmsOTPs().Send(context.TODO(), api.SmsCodeSendReq{
+ PhoneNumber: integration.CreateRandomTestPhoneNumber(t),
+ TemplateName: util.Ptr("default"),
+ Create: true,
+ ClientInfo: util.ClientInfo("foobar", "127.0.0.1"),
+ })
+
+ require.NoError(t, err)
+ assert.NotEmpty(t, rsp.Data.SmsCodeID)
+}
diff --git a/tests/integration/smsotp/sms_otp_validate_test.go b/tests/integration/smsotp/sms_otp_validate_test.go
new file mode 100644
index 0000000..4e9c6ba
--- /dev/null
+++ b/tests/integration/smsotp/sms_otp_validate_test.go
@@ -0,0 +1,71 @@
+//go:build integration
+
+package smsotp_test
+
+import (
+ "context"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/pkg/util"
+ "github.com/corbado/corbado-go/tests/integration"
+)
+
+func TestSmsOTPValidate_ValidationErrorEmptyCode(t *testing.T) {
+ _, err := integration.SDK(t).SmsOTPs().Validate(context.TODO(), "sms-123456789", api.SmsCodeValidateReq{
+ SmsCode: "",
+ })
+
+ require.Error(t, err)
+
+ serverErr := corbado.AsServerError(err)
+ require.NotNil(t, serverErr)
+ assert.Contains(t, servererror.GetValidationMessage(serverErr.Validation), "smsCode: cannot be blank")
+}
+
+func TestSmsOTPValidate_ValidationErrorInvalidCode(t *testing.T) {
+ _, err := integration.SDK(t).SmsOTPs().Validate(context.TODO(), "sms-123456789", api.SmsCodeValidateReq{
+ SmsCode: "1",
+ })
+
+ require.Error(t, err)
+
+ serverErr := corbado.AsServerError(err)
+ require.NotNil(t, serverErr)
+ assert.Contains(t, servererror.GetValidationMessage(serverErr.Validation), "smsCode: the length must be exactly 6")
+}
+
+func TestSmsOTPValidate_ValidationErrorInvalidID(t *testing.T) {
+ _, err := integration.SDK(t).SmsOTPs().Validate(context.TODO(), "sms-123456789", api.SmsCodeValidateReq{
+ SmsCode: "123456",
+ })
+
+ require.Error(t, err)
+
+ serverErr := corbado.AsServerError(err)
+ require.NotNil(t, serverErr)
+ assert.Equal(t, int32(404), serverErr.HTTPStatusCode)
+}
+
+func TestSmsOTPValidate_Success(t *testing.T) {
+ rsp, err := integration.SDK(t).SmsOTPs().Send(context.TODO(), api.SmsCodeSendReq{
+ PhoneNumber: integration.CreateRandomTestPhoneNumber(t),
+ TemplateName: util.Ptr("default"),
+ Create: true,
+ ClientInfo: util.ClientInfo("foobar", "127.0.0.1"),
+ })
+
+ require.NoError(t, err)
+ assert.NotEmpty(t, rsp.Data.SmsCodeID)
+
+ _, err = integration.SDK(t).SmsOTPs().Validate(context.TODO(), rsp.Data.SmsCodeID, api.SmsCodeValidateReq{
+ SmsCode: "150919",
+ })
+
+ require.NoError(t, err)
+}
diff --git a/tests/integration/template/email_template_create_test.go b/tests/integration/template/email_template_create_test.go
index 98d6c5e..65fdeee 100644
--- a/tests/integration/template/email_template_create_test.go
+++ b/tests/integration/template/email_template_create_test.go
@@ -6,12 +6,13 @@ import (
"context"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestEmailTemplateCreate_ValidationError(t *testing.T) {
@@ -31,11 +32,12 @@ func TestEmailTemplateCreate_ValidationError(t *testing.T) {
HtmlColorButtonFont: "#ffffff",
IsDefault: false,
})
+
require.Nil(t, rsp)
require.NotNil(t, err)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, "lang: must be in a valid format", servererror.GetValidationMessage(serverErr.Validation))
}
@@ -56,8 +58,8 @@ func TestEmailTemplateCreate_Success(t *testing.T) {
HtmlColorButtonFont: "#ffffff",
IsDefault: false,
})
+
require.Nil(t, err)
require.NotNil(t, rsp)
-
assert.NotEmpty(t, rsp.Data.EmailTemplateID)
}
diff --git a/tests/integration/template/sms_template_create_test.go b/tests/integration/template/sms_template_create_test.go
index b618485..dcdcf16 100644
--- a/tests/integration/template/sms_template_create_test.go
+++ b/tests/integration/template/sms_template_create_test.go
@@ -6,12 +6,13 @@ import (
"context"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestSMSTemplateCreate_ValidationError(t *testing.T) {
@@ -21,11 +22,12 @@ func TestSMSTemplateCreate_ValidationError(t *testing.T) {
TextPlain: "",
Type: api.SmsTemplateCreateReqTypeSmsCode,
})
+
require.Nil(t, rsp)
require.NotNil(t, err)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, "textPlain: cannot be blank", servererror.GetValidationMessage(serverErr.Validation))
}
diff --git a/tests/integration/user/user_create_test.go b/tests/integration/user/user_create_test.go
new file mode 100644
index 0000000..1aba165
--- /dev/null
+++ b/tests/integration/user/user_create_test.go
@@ -0,0 +1,41 @@
+//go:build integration
+
+package user_test
+
+import (
+ "context"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/pkg/util"
+ "github.com/corbado/corbado-go/tests/integration"
+)
+
+func TestUserCreate_ValidationError(t *testing.T) {
+ rsp, err := integration.SDK(t).Users().Create(context.TODO(), api.UserCreateReq{
+ Name: "",
+ Email: util.Ptr(""),
+ })
+
+ require.Nil(t, rsp)
+ require.Error(t, err)
+
+ serverErr := corbado.AsServerError(err)
+ require.NotNil(t, serverErr)
+ assert.Equal(t, "name: cannot be blank", servererror.GetValidationMessage(serverErr.Validation))
+}
+
+func TestUserCreate_Success(t *testing.T) {
+ rsp, err := integration.SDK(t).Users().Create(context.TODO(), api.UserCreateReq{
+ Name: integration.CreateRandomTestName(t),
+ Email: util.Ptr(integration.CreateRandomTestEmail(t)),
+ })
+
+ assert.NotNil(t, rsp)
+ assert.NoError(t, err)
+}
diff --git a/tests/integration/user/user_delete_test.go b/tests/integration/user/user_delete_test.go
new file mode 100644
index 0000000..e6e2258
--- /dev/null
+++ b/tests/integration/user/user_delete_test.go
@@ -0,0 +1,35 @@
+//go:build integration
+
+package user_test
+
+import (
+ "context"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/tests/integration"
+)
+
+func TestUserDelete_ValidationError(t *testing.T) {
+ rsp, err := integration.SDK(t).Users().Delete(context.TODO(), "usr-123456789", api.UserDeleteReq{})
+ require.Nil(t, rsp)
+ require.Error(t, err)
+
+ serverErr := corbado.AsServerError(err)
+ require.NotNil(t, serverErr)
+ assert.Equal(t, int32(400), serverErr.HTTPStatusCode)
+ assert.Equal(t, "userID: does not exist", servererror.GetValidationMessage(serverErr.Validation))
+}
+
+func TestUserDelete_Success(t *testing.T) {
+ userID := integration.CreateUser(t)
+
+ rsp, err := integration.SDK(t).Users().Delete(context.TODO(), userID, api.UserDeleteReq{})
+ require.NotNil(t, rsp)
+ require.NoError(t, err)
+}
diff --git a/tests/integration/user/user_get_test.go b/tests/integration/user/user_get_test.go
new file mode 100644
index 0000000..8f775c6
--- /dev/null
+++ b/tests/integration/user/user_get_test.go
@@ -0,0 +1,33 @@
+//go:build integration
+
+package user_test
+
+import (
+ "context"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/tests/integration"
+)
+
+func TestUserGet_NotFound(t *testing.T) {
+ rsp, err := integration.SDK(t).Users().Get(context.TODO(), "usr-123456789", &api.UserGetParams{})
+ require.Nil(t, rsp)
+ require.Error(t, err)
+
+ serverErr := corbado.AsServerError(err)
+ require.NotNil(t, serverErr)
+ assert.Equal(t, int32(404), serverErr.HTTPStatusCode)
+}
+
+func TestUserGet_Success(t *testing.T) {
+ userID := integration.CreateUser(t)
+
+ rsp, err := integration.SDK(t).Users().Get(context.TODO(), userID, &api.UserGetParams{})
+ require.NotNil(t, rsp)
+ require.NoError(t, err)
+}
diff --git a/tests/integration/user/user_list_test.go b/tests/integration/user/user_list_test.go
index e4e1198..b163e04 100644
--- a/tests/integration/user/user_list_test.go
+++ b/tests/integration/user/user_list_test.go
@@ -6,42 +6,45 @@ import (
"context"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
- "github.com/corbado/corbado-go/pkg/sdk/util"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/pkg/util"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestUserList_ValidationError(t *testing.T) {
- usersRsp, err := integration.SDK(t).Users().List(context.TODO(), &api.UserListParams{
+ rsp, err := integration.SDK(t).Users().List(context.TODO(), &api.UserListParams{
Sort: util.Ptr("foo:bar"),
})
- require.Nil(t, usersRsp)
- require.NotNil(t, err)
+ require.Nil(t, rsp)
+ require.Error(t, err)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, "sort: Invalid order direction 'bar'", servererror.GetValidationMessage(serverErr.Validation))
}
func TestUserList_Success(t *testing.T) {
- // send email link first so that we have at least one user
- _, err := integration.SDK(t).EmailLinks().Send(context.TODO(), api.EmailLinkSendReq{
- Email: integration.CreateRandomTestEmail(t),
- Redirect: "https://some.site.com/authenticate",
- TemplateName: util.Ptr("default"),
- Create: true,
- AdditionalPayload: util.Ptr("{}"),
- ClientInfo: util.ClientInfo("foobar", "127.0.0.1"),
+ userID := integration.CreateUser(t)
+
+ rsp, err := integration.SDK(t).Users().List(context.TODO(), &api.UserListParams{
+ Sort: util.Ptr("created:desc"),
})
- require.NoError(t, err)
- usersRsp, err := integration.SDK(t).Users().List(context.TODO(), nil)
require.NoError(t, err)
- assert.True(t, len(usersRsp.Data.Users) > 0)
+ found := false
+ for _, user := range rsp.Data.Users {
+ if user.ID == userID {
+ found = true
+ break
+ }
+ }
+
+ assert.True(t, found)
}
diff --git a/tests/integration/utils.go b/tests/integration/utils.go
index 342ea73..3aa302e 100644
--- a/tests/integration/utils.go
+++ b/tests/integration/utils.go
@@ -3,16 +3,18 @@
package integration
import (
+ "context"
"crypto/rand"
"math/big"
"os"
- "runtime"
- "strings"
"testing"
- "github.com/corbado/corbado-go"
"github.com/pkg/errors"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/util"
)
func SDK(t *testing.T) corbado.SDK {
@@ -26,15 +28,6 @@ func SDK(t *testing.T) corbado.SDK {
return sdk
}
-func getEnv(t *testing.T, name string) string {
- env := os.Getenv(name)
- if env == "" {
- t.Fatalf("Missing env variable %s", name)
- }
-
- return env
-}
-
func GetProjectID(t *testing.T) string {
return getEnv(t, "CORBADO_PROJECT_ID")
}
@@ -51,14 +44,14 @@ func CreateRandomTestEmail(t *testing.T) string {
value, err := generateString(10)
require.NoError(t, err)
- return getFunctionName() + value + "@test.de"
+ return "integration-test-" + value + "@corbado.com"
}
func CreateRandomTestPhoneNumber(t *testing.T) string {
- value, err := generateNumber(13)
+ value, err := generateNumber(7)
require.NoError(t, err)
- return "+49" + value
+ return "+491509" + value
}
func CreateRandomTestName(t *testing.T) string {
@@ -68,6 +61,16 @@ func CreateRandomTestName(t *testing.T) string {
return value
}
+func CreateUser(t *testing.T) string {
+ rsp, err := SDK(t).Users().Create(context.TODO(), api.UserCreateReq{
+ Name: CreateRandomTestName(t),
+ Email: util.Ptr(CreateRandomTestEmail(t)),
+ })
+ require.NoError(t, err)
+
+ return rsp.Data.UserID
+}
+
func generateString(length int) (string, error) {
// Removed I, 1, 0 and O because of risk of confusion
const letters = "ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijklmnopwrstuvwxyz23456789"
@@ -101,16 +104,11 @@ func generateNumber(length int) (string, error) {
return string(res), nil
}
-func getFunctionName() string {
- pc := make([]uintptr, 15)
- n := runtime.Callers(3, pc)
-
- frames := runtime.CallersFrames(pc[:n])
- frame, _ := frames.Next()
-
- functionName := frame.Function
- functionName = functionName[strings.LastIndex(functionName, ".")+1:]
- functionName = functionName[5:]
+func getEnv(t *testing.T, name string) string {
+ env := os.Getenv(name)
+ if env == "" {
+ t.Fatalf("Missing env variable %s", name)
+ }
- return functionName
+ return env
}
diff --git a/tests/integration/validation/validate_email_test.go b/tests/integration/validation/validate_email_test.go
index 10f8308..612359d 100644
--- a/tests/integration/validation/validate_email_test.go
+++ b/tests/integration/validation/validate_email_test.go
@@ -6,23 +6,25 @@ import (
"context"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestValidateEmail_ValidationError(t *testing.T) {
rsp, err := integration.SDK(t).Validations().ValidateEmail(context.TODO(), api.ValidateEmailReq{
Email: "",
})
+
require.Nil(t, rsp)
require.NotNil(t, err)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, "email: cannot be blank", servererror.GetValidationMessage(serverErr.Validation))
}
diff --git a/tests/integration/validation/validate_phone_number_test.go b/tests/integration/validation/validate_phone_number_test.go
index 9264d66..c714d80 100644
--- a/tests/integration/validation/validate_phone_number_test.go
+++ b/tests/integration/validation/validate_phone_number_test.go
@@ -6,23 +6,25 @@ import (
"context"
"testing"
- "github.com/corbado/corbado-go"
- "github.com/corbado/corbado-go/pkg/sdk/entity/api"
- "github.com/corbado/corbado-go/pkg/sdk/servererror"
- "github.com/corbado/corbado-go/tests/integration"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
+
+ "github.com/corbado/corbado-go"
+ "github.com/corbado/corbado-go/pkg/generated/api"
+ "github.com/corbado/corbado-go/pkg/servererror"
+ "github.com/corbado/corbado-go/tests/integration"
)
func TestValidatePhoneNumber_ValidationError(t *testing.T) {
rsp, err := integration.SDK(t).Validations().ValidatePhoneNumber(context.TODO(), api.ValidatePhoneNumberReq{
PhoneNumber: "",
})
+
require.Nil(t, rsp)
require.NotNil(t, err)
+
serverErr := corbado.AsServerError(err)
require.NotNil(t, serverErr)
-
assert.Equal(t, "phoneNumber: cannot be blank", servererror.GetValidationMessage(serverErr.Validation))
}
@@ -30,9 +32,9 @@ func TestValidatePhoneNumber_Success(t *testing.T) {
rsp, err := integration.SDK(t).Validations().ValidatePhoneNumber(context.TODO(), api.ValidatePhoneNumberReq{
PhoneNumber: integration.CreateRandomTestPhoneNumber(t),
})
+
require.Nil(t, err)
require.NotNil(t, rsp)
-
assert.True(t, rsp.Data.IsValid)
assert.Equal(t, api.PhoneNumberValidationResultValidationCodeValid, rsp.Data.ValidationCode)
assert.NotNil(t, rsp.Data.PhoneNumber)