You can use the access token issued when a user signs in through OpenID Connect to call APIs on that user's behalf, and refresh that token from a ViewModel when it has expired or before a new API operation.
What this feature does
When a user signs in through OpenID Connect, Turnkey can exchange the authorization code returned by the identity provider for tokens. It stores the resulting tokens as claims for that user:
| ClaimType | Purpose |
|---|---|
access_token
|
A short-lived token that you send when calling an API that accepts the signed-in user's delegated access. |
refresh_token
|
A longer-lived token that Turnkey uses to request a new access token without requiring another interactive sign-in. |
The claims are represented by SysUserClaim objects associated with the signed-in SysUser. For example, after a successful Azure AD sign-in, the user's claims can include both access_token and refresh_token, in addition to claims received from the identity provider.
This is a user-delegated token flow: the token represents the signed-in user and the API still enforces that user's permissions. For example, an API request for a document can succeed only when both the application registration and the signed-in user have permission to access that document.
Configure token acquisition
Configure OpenID Connect before users sign in. Put deployment-specific settings in App_Data/TurnkeySettingsOverride.xml so that an upgrade does not replace them. See Documentation:OpenID config for the complete OpenID Connect configuration and provider-specific setup.
The settings required for access-token refresh are:
| Setting | Required value or purpose |
|---|---|
OpenID_TokenEndPoint
|
The identity provider's token endpoint. Turnkey uses this endpoint to exchange the authorization code and later refresh the access token. |
OpenIDConnectScope
|
Must include offline_access when using Azure AD. Include the OpenID and API scopes that your sign-in and API call require.
|
SharedSecret
|
A secret that Turnkey uses to encrypt the stored tokens in the database. Keep this value private and outside the application model. |
Example settings structure:
<OpenID_TokenEndPoint>yourserverTokenEndpointUsuallyEndsLikeThis/oauth2/v2.0/token</OpenID_TokenEndPoint>
<OpenIDConnectScope>offline_access openid profile</OpenIDConnectScope>
<SharedSecret>Secret</SharedSecret>
For Azure AD, offline_access is required for Azure AD to issue a refresh token. Without a refresh token, Turnkey cannot obtain a new access token after the current one expires; the user must sign in again.
Also configure the identity provider with the exact callback URL used by Turnkey. A callback ending in /signin-oidc helps the middleware recognize the provider's login callback. The provider must allow the configured redirect URL. See Documentation:OpenID config for redirect URL guidance and Documentation:How does OpenIdConnect work for the authorization-code flow.
Refresh the access token from a ViewModel
Add the following method to SysUser in your model:
OpenIdConnectAccessTokenRefresh():String (TV: Eco.ExternalLateBound)
Call this method before an operation that requires a current access token.
- Identify the
SysUserfor the signed-in user. - Call
OpenIdConnectAccessTokenRefresh()on that user. - Check the returned string.
- If the result is
ok, read the updatedSysUserClaimvalues whoseClaimTypevalues areaccess_tokenandrefresh_token. - Use the current
access_tokenfor the API request. - If the result is an error, do not continue with the API request. Handle the error and require the user to sign in again when a valid refresh token is no longer available.
The access token is short-lived. Refresh it before starting a new API operation rather than assuming a token obtained at login is still valid. A refresh can also return an updated refresh token, so always use the claim values after a successful refresh instead of retaining an older token value.
Example operation sequence
A document integration that calls a delegated API can follow this sequence:
- The user signs in through OpenID Connect.
- Turnkey receives the authorization code at the configured callback and obtains the initial tokens.
- Turnkey stores the encrypted token values as the user's claims.
- Before requesting a document, the ViewModel calls
OpenIdConnectAccessTokenRefresh(). - When the method returns
ok, the ViewModel uses the updatedaccess_tokenin its API request.
If the refresh token has been revoked, has expired, or is otherwise no longer accepted by the identity provider, a refresh cannot restore access. The user must sign out and sign in again so that the provider can issue a new authorization code and, where permitted, a new refresh token.
Security and operational requirements
- Treat both token claims as credentials. Do not expose them in UI, logs, diagnostics, or client-side data.
- Set a private, deployment-specific
SharedSecret. It encrypts the stored tokens and is particularly important because refresh tokens can remain usable longer than access tokens. - Keep the shared secret outside the model and restrict access to the Turnkey settings files and database backups.
- Request only the API scopes needed by the integration. The identity provider's application registration must also be permitted to use the target API.
- Configure each environment's permitted redirect URL at the identity provider. Local, test, and production URLs are distinct values.
Troubleshooting
| Symptom | Check |
|---|---|
No refresh_token claim after sign-in
|
Confirm that OpenIDConnectScope contains offline_access for Azure AD and that the identity provider accepted the requested scope.
|
| Refresh returns an error | Confirm OpenID_TokenEndPoint, the application secret, and provider configuration. The refresh token may also have expired or been revoked; sign in again.
|
| Login returns to the application but the authorization code is not handled | Confirm that the configured and provider-registered redirect URLs match exactly. Use a redirect ending in /signin-oidc when applicable.
|
| API request is denied although token refresh succeeds | Check both the application registration's granted API permissions and the signed-in user's permission to the requested resource. |
For OpenID Connect logging and diagnosis of the authorization-code callback, see Documentation:How does OpenIdConnect work.
Scope of this page
This page covers refreshing tokens obtained through an interactive OpenID Connect user login. Do not use this pattern for server-to-server access with no signed-in user; use HowTos:Oauth2 Client Credentials Grant Flow instead. For the earlier Office 365-specific approach and Graph API background, see Documentation:Office365 accesstoken.
