Skip to content

Commit

Permalink
Merge pull request #362 from okta/jwt-authorization-mode
Browse files Browse the repository at this point in the history
add jwt as an authorization mode
  • Loading branch information
duytiennguyen-okta authored Feb 8, 2023
2 parents 5d77dae + 084a2c5 commit 9383ac5
Show file tree
Hide file tree
Showing 10 changed files with 689 additions and 211 deletions.
387 changes: 284 additions & 103 deletions .generator/templates/client.mustache

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions .generator/templates/configuration.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ type Configuration struct {
Token string `yaml:"token" envconfig:"OKTA_CLIENT_TOKEN"`
AuthorizationMode string `yaml:"authorizationMode" envconfig:"OKTA_CLIENT_AUTHORIZATIONMODE"`
ClientId string `yaml:"clientId" envconfig:"OKTA_CLIENT_CLIENTID"`
ClientAssertion string `yaml:"clientAssertion" envconfig:"OKTA_CLIENT_CLIENTASSERTION"`
Scopes []string `yaml:"scopes" envconfig:"OKTA_CLIENT_SCOPES"`
PrivateKey string `yaml:"privateKey" envconfig:"OKTA_CLIENT_PRIVATEKEY"`
PrivateKeyId string `yaml:"privateKeyId" envconfig:"OKTA_CLIENT_PRIVATEKEYID"`
Expand Down
19 changes: 19 additions & 0 deletions .generator/templates/private_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,22 @@ func Test_Private_Key_Request_Can_Create_User(t *testing.T) {
require.NoError(t, err, "Creating a new user should not error")
assert.NotNil(t, user, "User should not be nil")
}

func Test_JWT_Request_Can_Create_User(t *testing.T) {
if os.Getenv("OKTA_TRAVIS_CI") != "yes" {
t.Skip("Skipping testing not in CI environment")
}
configuration := NewConfiguration(WithAuthorizationMode("JWT"), WithScopes([]string{"okta.users.manage"}))
privateKeySigner, err := createKeySigner(configuration.Okta.Client.PrivateKey, configuration.Okta.Client.PrivateKeyId)
require.NoError(t, err)
clientAssertion, err := createClientAssertion(configuration.Okta.Client.OrgUrl, configuration.Okta.Client.ClientId, privateKeySigner)
require.NoError(t, err)
configuration.Okta.Client.ClientAssertion = clientAssertion
client := NewAPIClient(configuration)
uc := testFactory.NewValidTestUserCredentialsWithPassword()
profile := testFactory.NewValidTestUserProfile()
body := CreateUserRequest{Credentials: uc, Profile: profile}
user, _, err := client.UserApi.CreateUser(apiClient.cfg.Context).Body(body).Execute()
require.NoError(t, err, "Creating a new user should not error")
assert.NotNil(t, user, "User should not be nil")
}
40 changes: 39 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -859,8 +859,9 @@ The client is configured with a configuration setter object passed to the `NewCl
| WithRequestTimeout(requestTimeout int64) | HTTP request time out in seconds |
| WithRateLimitMaxRetries(maxRetries int32) | Number of request retries when http request times out |
| WithRateLimitMaxBackOff(maxBackoff int64) | Max amount of time to wait on request back off |
| WithAuthorizationMode(authzMode string) | Okta API auth mode, `SSWS` (Okta based) or `PrivateKey` (OAuth app based) |
| WithAuthorizationMode(authzMode string) | Okta API auth mode, `SSWS` (Okta based), `PrivateKey` (OAuth app based) or `JWT` (OAuth app based) |
| WithClientId(clientId string) | Okta App client id, used with `PrivateKey` OAuth auth mode |
| WithClientAssertion(clientAssertion string) | Okta App client assertion, used with `JWT` OAuth auth mode |
| WithScopes(scopes []string) | Okta API app scopes |
| WithPrivateKey(privateKey string) | Private key value |
| WithPrivateKeyId(privateKeyId string) | Private key id (kid) value |
Expand Down Expand Up @@ -1055,6 +1056,43 @@ ctx, client, err := okta.NewClient(ctx,
```

### OAuth 2.0 With JWT Key
Okta allows you to interact with Okta APIs using scoped OAuth 2.0 access
tokens. Each access token enables the bearer to perform specific actions on
specific Okta endpoints, with that ability controlled by which scopes the
access token contains.

Access Tokens are always cached and respect the `expires_in` value of an access
token response.

This SDK supports this feature only for service-to-service applications. Check
out [our
guides](https://developer.okta.com/docs/guides/implement-oauth-for-okta/overview/)
to learn more about how to register a new service application using a private
and public key pair. Otherwise, follow the example steps at the end of this
topic.

When using this approach you won't need an API Token because the SDK will
request an access token for you. In order to use OAuth 2.0, construct a client
instance by passing the following parameters:

```go
ctx := context.TODO()
ctx, client, err := okta.NewClient(ctx,
okta.WithOrgUrl("https://{yourOktaDomain}"),
okta.WithAuthorizationMode("JWT"),
okta.WithClientAssertion("{{clientAssertion}}"),
okta.WithScopes(([]string{"okta.users.manage"})),
)
if err != nil {
fmt.Printf("Error: %v\n", err)
}
fmt.Printf("Context: %+v\n Client: %+v\n\n",ctx, client)
```

This is very similar to PrivateKey Authorization Mode with a caveat, instead of providing public/privatekey pair, you can use a pre-signed JWT instead

### OAuth 2.0 With Bearer Token

Okta SDK supports authorization using a `Bearer` token. A bearer token is an
Expand Down
7 changes: 7 additions & 0 deletions okta/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ type config struct {
Scopes []string `yaml:"scopes" envconfig:"OKTA_CLIENT_SCOPES"`
PrivateKey string `yaml:"privateKey" envconfig:"OKTA_CLIENT_PRIVATEKEY"`
PrivateKeyId string `yaml:"privateKeyId" envconfig:"OKTA_CLIENT_PRIVATEKEYID"`
ClientAssertion string `yaml:"clientAssertion" envconfig:"OKTA_CLIENT_CLIENTASSERTION"`
} `yaml:"client"`
Testing struct {
DisableHttpsCheck bool `yaml:"disableHttpsCheck" envconfig:"OKTA_TESTING_DISABLE_HTTPS_CHECK"`
Expand Down Expand Up @@ -189,6 +190,12 @@ func WithClientId(clientId string) ConfigSetter {
}
}

func WithClientAssertion(clientAssertion string) ConfigSetter {
return func(c *config) {
c.Okta.Client.ClientAssertion = clientAssertion
}
}

func WithScopes(scopes []string) ConfigSetter {
return func(c *config) {
c.Okta.Client.Scopes = scopes
Expand Down
13 changes: 13 additions & 0 deletions okta/okta.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 9383ac5

Please sign in to comment.