/okta-sdk-golang

okta-sdk-golang

Primary LanguageGoOtherNOASSERTION

Build Status Beta Release License Support API Reference

Okta Golang management SDK

This repository contains the Okta management SDK for Golang. This SDK can be used in your server-side code to interact with the Okta management API and

We also publish these libraries for Golang:

You can learn more on the Okta + Golang page in our documentation.

Release status

This library uses semantic versioning and follows Okta's library version policy.

Version Status
0.x ⚠️ Beta Release (Retired)
1.x ✔️ Release

The latest release can always be found on the releases page.

Need help?

If you run into problems using the SDK, you can

Getting started

To install the Okta Golang SDK in your project, run go get github.com/okta/okta-sdk-golang/okta

You'll also need

Construct a client instance by passing it your Okta domain name and API token:

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))

Hard-coding the Okta domain and API token works for quick tests, but for real projects you should use a more secure way of storing these values (such as environment variables). This library supports a few different configuration sources, covered in the configuration reference section.

Extending the Client

When calling okta.NewClient() we allow for you to pass custom instances of http.Client and cache.Cache.

myClient := &http.Client{}

myCache := NewCustomCacheDriver()

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"), okta.WithHttpClient(myClient), okta.WithCacheManager(myCache))

Extending or Creating New Cache Manager

You can create a custom cache driver by implementing cache.Cache

type CustomCacheDriver struct {
}

func NewCustomCacheDriver() Cache {
	return CustomCacheDriver{}
}

func (c CustomCacheDriver) Get(key string) *http.Response {
	return nil
}

func (c CustomCacheDriver) Set(key string, value *http.Response) {}

func (c CustomCacheDriver) Delete(key string) {}

func (c CustomCacheDriver) Clear() {}

func (c CustomCacheDriver) Has(key string) bool {
	return false
}

Usage guide

These examples will help you understand how to use this library. You can also browse the full API reference documentation.

Once you initialize a client, you can call methods to make requests to the Okta API. Most methods are grouped by the API endpoint they belong to. For example, methods that call the Users API are organized under client.User.

Authenticate a User

This library should only be used with the Okta management API. To call the Authentication API, you should construct your own HTTP requests.

Get a User

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))
user, resp, err := client.User.GetUser(user.Id, nil)

List all Users

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))
users, resp, err := client.User.ListUsers()

Filter or search for Users

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))

filter := query.NewQueryParams(query.WithFilter("status eq \"ACTIVE\""))

users, resp, err := client.User.ListUsers(filter)

Create a User

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))

p := &okta.PasswordCredential{
		Value: "Abcd1234",
}
uc := &okta.UserCredentials{
		Password: p,
}
profile := okta.UserProfile{}
profile["firstName"] = "John"
profile["lastName"] = "Activate"
profile["email"] = "john-activate@example.com"
profile["login"] = "john-activate@example.com"
u := &okta.User{
		Credentials: uc,
		Profile:     &profile,
}

user, resp, err := client.User.CreateUser(*u, nil)

Update a User

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))

newProfile := *user.Profile
newProfile["nickName"] = "Batman"
updatedUser := &okta.User{
  Profile: &newProfile,
}
user, resp, err := client.User.UpdateUser(user.Id, *updatedUser, nil)

Get and set custom attributes

Custom attributes must first be defined in the Okta profile editor. Then, you can work with custom attributes on a user:

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))
user, resp, err := client.User.GetUser(user.Id, nil)

nickName = user.Profile["nickName"]

Remove a User

You must first deactivate the user, and then you can delete the user.

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))
resp, err := client.User.DeactivateUser(user.Id, nil)

resp, err := client.User.DeactivateOrDeleteUser(user.Id, nil)

List a User's Groups

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))

groups, resp, err := client.User.ListUserGroups(user.Id, nil)

Create a Group

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))

gp := &okta.GroupProfile{
  Name: "Get Test Group",
}
g := &okta.Group{
  Profile: gp,
}
group, resp, err := client.Group.CreateGroup(*g, nil)

Add a User to a Group

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))

resp, err := client.Group.AddUserToGroup(group.Id, user.Id, nil)

List a User's enrolled Factors

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))

allowedFactors, resp, err := client.Factor.ListSupportedFactors(user.Id)

Enroll a User in a new Factor

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))

factorProfile := okta.NewSmsFactorProfile()
factorProfile.PhoneNumber = "5551234567"

factor := okta.NewSmsFactor()
factor.Profile = factorProfile

addedFactor, resp, err := client.Factor.AddFactor(user.Id, factor, nil)

Activate a Factor

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))

factor, resp, err := client.Factor.ActivateFactor(user.Id, factor.Id, nil)

Verify a Factor

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))

verifyFactorRequest := okta.VerifyFactorRequest{
  PassCode: "123456"
}
verifyFactorResp, resp, err := client.Factor.VerifyFactor(user.Id, factor.Id, verifyFactorRequest, nil)

List all Applications

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))

applications, resp, err := client.Application.ListApplications(nil)

//applications will need to be cast from the interface into its concrete form before you can use it.
for _, a := range applications {
		if a.(*okta.Application).Name == "bookmark" {
			if a.(*okta.Application).Id == app2.(okta.BookmarkApplication).Id {
				application :=  *a.(*okta.BookmarkApplication) //This will cast it to a Bookmark Application
			}
		}
		// continue for each type you want to work with.
	}

Get an Application

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))

//Getting a Basic Auth Application
application, resp, err = client.Application.GetApplication(appId, okta.NewBasicAuthApplication(), nil)

//To use the application, you must cast it to the type.
app := application.(*okta.BasicAuthApplication)

Create a SWA Application

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))

swaAppSettingsApp := newSwaApplicationSettingsApplication()
swaAppSettingsApp.ButtonField = "btn-login"
swaAppSettingsApp.PasswordField = "txtbox-password"
swaAppSettingsApp.UsernameField = "txtbox-username"
swaAppSettingsApp.Url = "https://example.com/login.html"
swaAppSettingsApp.LoginUrlRegex = "REGEX_EXPRESSION"

swaAppSettings := newSwaApplicationSettings()
swaAppSettings.App = &swaAppSettingsApp

swaApp := newSwaApplication()
swaApp.Label = "Test App"
swaApp.Settings = &swaAppSettings

application, resp, err := client.Application.CreateApplication(swaApp, nil)

Call other API endpoints

Not every API endpoint is represented by a method in this library. You can call any Okta management API endpoint using this generic syntax:

client := okta.NewClient(context, okta.WithOrgUrl("https://{yourOktaDomain}"), okta.WithToken("{apiToken}"))

url := "https://golang.oktapreview.com/api/v1/authorizationServers

type Signing struct {
	RotationMode string     `json:"rotationMode,omitempty"`
	LastRotated  *time.Time `json:"lastRotated,omitempty"`
	NextRotation *time.Time `json:"nextRotation,omitempty"`
	Kid          string     `json:"kid,omitempty"`
}

type Credentials struct {
	Signing *Signing `json:"signing,omitempty"`
}

type AuthorizationServer struct {
	Id          string       `json:"id,omitempty"`
	Name        string       `json:"name,omitempty"`
	Description string       `json:"description,omitempty"`
	Audiences   []string     `json:"audiences,omitempty"`
	Issuer      string       `json:"issuer,omitempty"`
	IssuerMode  string       `json:"issuerMode,omitempty"`
	Status      string       `json:"status,omitempty"`
	Created     *time.Time   `json:"created,omitempty"`
	LastUpdated *time.Time   `json:"lastUpdated,omitempty"`
	Credentials *Credentials `json:"credentials,omitempty"`
	Embedded    interface{}  `json:"_embedded,omitempty"`
	Links       interface{}  `json:"_links,omitempty"`
}

as := AuthorizationServer{
  Name:        "Sample Authorization Server",
  Description: "Sample Authorization Server description",
  Audiences:   []string{"api://default"},
}

req, err := m.client.requestExecutor.NewRequest("POST", url, as)
if err != nil {
  return nil, nil, err
}

var authServer *AuthorizationServer
resp, err := m.client.requestExecutor.Do(req, &authServer)
if err != nil {
  return nil, resp, err
}
return authServer, resp, nil

Configuration reference

This library looks for configuration in the following sources:

  1. An okta.yaml file in a .okta folder in the current user's home directory (~/.okta/okta.yaml or %userprofile\.okta\okta.yaml)
  2. An okta.yaml file in a .okta folder in the application or project's root directory
  3. Environment variables
  4. Configuration explicitly passed to the constructor (see the example in Getting started)

Higher numbers win. In other words, configuration passed via the constructor will override configuration found in environment variables, which will override configuration in okta.yaml (if any), and so on.

YAML configuration

The full YAML configuration looks like:

okta:
  client:
    connectionTimeout: 30 # seconds
    orgUrl: "https://{yourOktaDomain}"
    proxy:
      port: null
      host: null
      username: null
      password: null
    token: {apiToken}

Environment variables

Each one of the configuration values above can be turned into an environment variable name with the _ (underscore) character:

  • OKTA_CLIENT_CONNECTIONTIMEOUT
  • OKTA_CLIENT_TOKEN
  • and so on

Building the SDK

In most cases, you won't need to build the SDK from source. If you want to build it yourself, you'll need these prerequisites:

  • Clone the repo
  • Run make build from the root of the project

Contributing

We're happy to accept contributions and PRs! Please see the contribution guide to understand how to structure a contribution.