This library is built for server-side projects in .NET to communicate with Okta as an OAuth 2.0 + OpenID Connect provider. It works with the Okta's Identity Engine to authenticate and register users.
To see this library working in a sample, check out our ASP.NET Samples. You can also check out our guides for step-by-step instructions — for both embedded SDK and embedded widget samples, get started with Run the sample apps.
❕ The use of this SDK requires usage of the Okta Identity Engine. This functionality is in general availability but is being gradually rolled out to customers. If you want to request to gain access to the Okta Identity Engine, please reach out to your account manager. If you do not have an account manager, please reach out to [email protected] for more information.
This library is currently GA. See release status for more information.
- Release status
- Need help?
- Getting started
- Usage guide
- Configuration reference
- Building the SDK
- Contributing
This library uses semantic versioning and follows Okta's Library Version Policy.
✔️ The current stable major version series is: 2.x
Version | Status |
---|---|
2.x | ✔️ Stable |
The latest release can always be found on the releases page.
If you run into problems using the SDK, you can
- Ask questions on the Okta Developer Forums
- Post issues here on GitHub (for code errors)
You will need:
- An Okta account, called an organization (sign up for a free developer organization if you need one)
These examples will help you understand how to use this library.
Once you initialize a Client
, you can call methods to make requests to the Okta API. Check out the Configuration reference section for more details.
var client = new IdxClient(new IdxConfiguration()
{
Issuer = "{YOUR_ISSUER}", // e.g. https://foo.okta.com/oauth2/default, https://foo.okta.com/oauth2/ausar5vgt5TSDsfcJ0h7
ClientId = "{YOUR_CLIENT_ID}",
ClientSecret = "{YOUR_CLIENT_SECRET}", //Required for confidential clients.
Scopes = new List<string> { "openid", "profile", "offline_access" },
RedirectUri = "{YOUR_REDIRECT_URI}", // Must match the redirect uri in client app settings/console
});
The request context object specifies the headers to be used in methods that bootstraps a new authentication flow. In other words, these headers are only sent when calling the /interact endpoint.
var requestContext = new RequestContext
{
DeviceToken = "deviceToken",
OktaUserAgentExtended = "MyXUserAgent",
XForwardedFor = "10.1.1.1",
};
var authResponse = await _idxClient..AuthenticateAsync(authenticationOptions: options, requestContext: requestContext).ConfigureAwait(false);
Note: The
x-device-token
andx-forwarded-for
headers will be only included for confidential clients.
var authnOptions = new AuthenticationOptions
{
Username = "[email protected]",
Password = "superSecretPassword",
};
var authnResponse = await _idxClient.AuthenticateAsync(authnOptions).ConfigureAwait(false);
if (authn.AuthenticationStatus == AuthenticationStatus.Success)
{
var accessToken = authnResponse.TokenInfo.AccessToken;
}
var authnOptions = new AuthenticationOptions
{
ActivationToken = "myToken",
};
var authnResponse = await _idxClient.AuthenticateAsync(authnOptions).ConfigureAwait(false);
if (authn.AuthenticationStatus == AuthenticationStatus.AwaitingAuthenticatorEnrollment)
{
// Redirect users to the enrollment view
}
The AuthenticationResponse
you get when using the IdxClient
will indicate how to proceed to continue with the authentication flow. When using the AuthenticateAsync
method you can get the following statuses:
Type: AuthenticationStatus.Success
The user was successfully authenticated and you can retrieve the tokens from the response by calling authnResponse.TokenInfo
.
Type: AuthenticationStatus.PasswordExpired
The user needs to change their password to continue with the authentication flow and retrieve tokens. Check for possible messages to the user by calling authnResponse.Messages
and authnResponse.CanSkip
to verify the user can skip the current step in the authentication process.
Type: AuthenticationStatus.AwaitingAuthenticatorEnrollment
The user needs to enroll an authenticator to continue with the authentication flow and retrieve tokens. You can retrieve the authenticators information by calling authnResponse.Authenticators
.
Type: AwaitingChallengeAuthenticatorSelection
The user needs to select and challenge an additional authenticator to continue with the authentication flow and retrieve tokens. You can retrieve the authenticators information by calling authnResponse.Authenticators
.
There other statuses that you can get when calling other methods of the IdxClient
:
Type: AwaitingChallengeAuthenticatorPollResponse
The user needs to acknowledge the pushe request sent by Okta Verify.
Type: AwaitingAuthenticatorVerification
The user has successfully selected an authenticator to challenge so they now need to verify the selected authenticator. For example, if the user selected phone, this status indicates that they have to provide they code they received to verify the authenticator.
Type: AwaitingAuthenticatorEnrollmentData
The user needs to provide additional authenticator information. For example, when a user selects to enroll phone they will have to provide their phone number to complete the enrollment process. You can retrieve current authenticator information by calling authnResponse.CurrentAuthenticator
.
Type: AwaitingChallengeAuthenticatorData
The user needs to provide additional authenticator information. For example, when a user selects to challenge phone they will have to choose if they want to receive the code via voice or SMS. You can retrieve current authenticator enrollment information by calling authnResponse.CurrentAuthenticatorEnrollment
.
Type: AwaitingPasswordReset
The user needs to reset their password to continue with the authentication flow and retrieve tokens.
await _idxClient.RevokeTokensAsync(TokenType.AccessToken, accessToken);
// UserProfile is a dynamic class that allows you set properties dinamically
var userProfile = new UserProfile();
userProfile.SetProperty("firstName", model.FirstName);
userProfile.SetProperty("lastName", model.LastName);
userProfile.SetProperty("email", model.Email);
var registerResponse = await _idxClient.RegisterAsync(userProfile);
if (registerResponse.AuthenticationStatus == AuthenticationStatus.Success)
{
// Retrieve tokens
}
Note: Check the response's
AuthenticatonStatus
property to determine what the next step is.
var recoverPasswordOptions = new RecoverPasswordOptions { Username = model.UserName, };
var authnResponse = await _idxClient.RecoverPasswordAsync(recoverPasswordOptions);
Note: Check the response's
AuthenticatonStatus
property to determine what the next step is.
The SDK throws an OktaException
everytime the server responds with an invalid status code, or there is an internal error. You can get more information by calling exception.Message
.
UnexpectedRemediationException
is an OktaException
derived class that usually indicates inconsistencies in the configuration. It is recommended to verify your policy configuration when you face with this error.
RedeemInteractionCodeException
is an OktaException
derived class that indicates there was an error when redeeming the interaction code.
TerminalStateException
is an OktaException
derived class that indicates that the user cannot continue the current flow, possibly due to an error or required additional actions outside of the authentication flow.
This exception object contains an array of messages that can be shown to the user as they are. Each message object in the array also contains a key property that can be used for internationalization. Here is an example of accessing the exception data. All the properties can be null. Null checks are not shown in the example.
try
{
// Trying to sign-on with a non-existent user name.
// The exact error depends on the Org settings and may differ.
}
catch (TerminalStateException exception)
{
string combinedTextMessage = exception.Message; // "There is no account with the Username [email protected]."
IList<IMessage> allMessages = exception.IdxMessages.Messages;
IMessage firstMessage = allMessages.First();
string firstMessageText = firstMessage.Text; // "There is no account with the Username [email protected]."
IIdxI18n firstMessageI18nInfo = firstMessage.I18n;
string firstMessageI18nKey = firstMessageI18nInfo.Key; // "idx.unknown.user"
IList<string> firstMessageI18nParams = firstMessageI18nInfo.Params; // an empty list
//.........................
}
For more usage examples check out our ASP.NET Sample Application.
This library looks for configuration in the following sources:
- As a YAML file in your home directory
- As part of an appsettings.json file in your application’s working directory
- As a YAML file in your application’s working directory
- In environment variables
- In the client constructor for the application (see the example in Getting started)
This is the order that the locations are searched for configuration information. If information is set in more than one location, it is overwritten so if, for example, the Issuer is set in both an okta.yaml file and in environment variables, the value in the environment variables takes precedence. If the Issuer was also set in the client constructor, that value would be used instead of either of the other two.
Note: To avoid confusion as to which configuration values are used by the SDK, you should use only one configuration option in your solution.
The SDK will look for a YAML file named okta.yaml
in:
- A folder called .okta whose parent is the current user's home directory
- On Mac/Linux, this is
~/.okta/okta.yaml
- On Windows, this is
%userprofile%\.okta\okta.yaml
- On Mac/Linux, this is
- The application's current working directory
- If you're using the recommended IISExpress debugger in Visual Studio to run your app, this is
${IIS Express install location}\IIS Express
, for example,C:\Program Files\IIS Express\okta.yaml
.
- If you're using the recommended IISExpress debugger in Visual Studio to run your app, this is
The information in the YAML file should be formatted as follows:
okta:
idx:
issuer: "{YOUR_ISSUER}"
clientId: "{YOUR_CLIENT_ID}"
clientSecret: "{YOUR_CLIENT_SECRET}"
scopes:
- "openid"
- "profile"
- "offline_access"
redirectUri: "{YOUR_REDIRECT_URI}"
The SDK will look for a JSON file named appsettings.json
in:
- The application’s current working directory
- If you're using the recommended IISExpress debugger in Visual Studio to run your app, this is
${IIS Express install location}\IIS Express
, for example,C:\Program Files\IIS Express\appsettings.json
.
- If you're using the recommended IISExpress debugger in Visual Studio to run your app, this is
The information in the JSON file should be formatted as follows:
{
"okta": {
"idx": {
"issuer" : "{YOUR_ISSUER}",
"clientId" : "{YOUR_CLIENT_ID}",
"clientSecret": "{YOUR_CLIENT_SECRET}",
"redirectUri": "{YOUR_REDIRECT_URI}",
"scopes": [ "openid", "profile", "offline_access" ]
}
}
}
The SDK will search your machine’s environment variables for any of the following keys:
OKTA_IDX_ISSUER
OKTA_IDX_CLIENTID
OKTA_IDX_CLIENTSECRET
OKTA_IDX_REDIRECTURI
Environment variables hold only single values so you need to create one for each scope you need to give to your application.
OKTA_IDX_SCOPES_0 = "openid"
OKTA_IDX_SCOPES_1 = "profile"
OKTA_IDX_SCOPES_2 = "offline_access"
In most cases, you won't need to build the SDK from source. If you want to build it yourself just clone the repo and compile using Visual Studio.
We are happy to accept contributions and PRs! Please see the contribution guide to understand how to structure a contribution.