# Authentication

> Fix 401 Unauthorized and failed token requests: OAuth off, no authorization header, grant type not allowed, invalid secret, redirect URI, lost admin password.

- **Product:** DS Server
- **Section:** Documentation
- **Kind:** Topic
- **Path:** DS Server > Troubleshooting > Authentication
- **2214 words**
- **Web URL:** https://docs.textcontrol.com/ds-server/troubleshooting/authentication/
- **LLMs URL:** https://docs.textcontrol.com/ds-server/troubleshooting/authentication/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/ds-server/troubleshooting/authentication/llms-full.txt

---

DS Server protects its services with OAuth: an application requests an access token at `/oauth/token` with the client ID and client secret of a security profile, and sends the token with every request. When a token request fails, DS Server answers with status 400 and a JSON object whose `error` and `error_description` name the cause. When a request with a token is refused, it answers with 401 and an empty body. The problems below are ordered from the admin portal settings to the token and the requests that use it; the responses are those of DS Server 5.0.2.

### Requests Work Without a Token

Requests to the Web API succeed, or reach the license check, without an `Authorization` header or with any token at all.

OAuth is switched off after a new installation: the **Security Profiles** page of the admin portal shows the switch **OAuth disabled** in red. As long as it is off, DS Server doesn't check tokens, and anyone who can reach the server can use it.

1. Open the admin portal and select **Security Profiles**.
2. Click the switch so that it shows **OAuth enabled** in green. The setting is saved at once.
3. Send a request without a token and check that it now returns 401.

[Enable OAuth](https://docs.textcontrol.com/ds-server/administration/oauth/llms-full.txt) describes the switch and when to leave OAuth off.

### Requests Return 401 Unauthorized

With OAuth enabled, a request returns `HTTP/1.1 401 Unauthorized` with an empty body.

The response headers tell the cases apart:

- **`WWW-Authenticate: Bearer`** in the response: the request had no token.
- **No `WWW-Authenticate` header**: the request had a token that DS Server doesn't accept. The token is unknown, has expired, or belongs to a security profile whose expiry date has passed. For an expired profile, `/oauth/token` still returns a token, but every request with it returns 401.

The DS Server log adds `TXTextControl was not authenticated. Failure message: Access not granted.` for a refused token, and `TXTextControl was not authenticated. Failure message: OAuth authorization: No authorization header, access token query parameter or access token cookie found.` for a request without a token.

1. Send the token in the header `Authorization: Bearer <access token>`, as the query parameter `access_token` or in a cookie named `access_token`.
2. Request a new token when the old one has expired. The token response names its lifetime in seconds in `expires_in`, `"3600"` in DS Server 5.0.
3. Open the security profile in the admin portal and clear its **Expiry date**, or set a later one. After the expiry date is cleared, the tokens of the profile are accepted again.

### The Token Request Reports a Missing Authorization Header

`POST /oauth/token` returns 400 with:

```json
{
  "error": "invalid_request",
  "error_description": "Missing authorization header."
}
```

For the client credentials grant type, DS Server expects the client ID and secret in an HTTP Basic `Authorization` header. Sending them only as the form fields `client_id` and `client_secret` isn't enough.

1. Send the credentials as Basic authorization, for example with the `--user` option of curl:

    ```bash
    curl --request POST 'http://localhost:5000/oauth/token' \
        --user '<client id>:<client secret>' \
        --data-urlencode grant_type=client_credentials
    ```
2. Send the body as form data (`application/x-www-form-urlencoded`). A JSON body returns `405 Method Not Allowed`.

The [POST /oauth/token](https://docs.textcontrol.com/ds-server/reference/web-api/oauth/token/post/llms-full.txt) reference lists the parameters of each grant type.

### The Token Request Says the Grant Type Isn't Allowed

`POST /oauth/token` returns 400 with:

```json
{
  "error": "unsupported_grant_type",
  "error_description": "This security profile does not allow the specified grant type. (client_credentials)"
}
```

A Document Editor that you initialize in JavaScript with a client ID and secret shows nothing, and the browser console reports:

```text
Could not retrieve OAuth token. Error: unsupported_grant_type, error description: This security profile does not allow the specified grant type. (client_credentials)
```

An ASP.NET Core application that uses the Document Editor or Document Viewer package without a `RedirectUri` shows this in place of the component:

```text
Authorization Error
Exception: OAuth access token request failed. error: "unsupported_grant_type", error_description: "This security profile does not allow the specified grant type. (client_credentials)"
```

The client credentials grant type is off for each new security profile. It is used whenever the client ID and secret are sent directly for a token: by your own requests, by the ASP.NET Core packages without a `RedirectUri`, and by the Angular and React packages and `TXTextControl.init` with a client ID and secret.

1. On the **Security Profiles** page of the admin portal, open the profile with its **Edit profile** icon.
2. Turn on the switch **Allow “Client Credentials” grant type** and click **Save**.

In a browser component, the client credentials are part of the page and visible to every visitor. To keep them on your server, request the token there and pass only the access token to the component, as [Client-Side Libraries](https://docs.textcontrol.com/ds-server/client-libraries/overview/#authorize-a-library) describes. [OAuth Grant Types](https://docs.textcontrol.com/ds-server/administration/oauth-grant-types/llms-full.txt) explains the switch.

### The Token Request Reports an Invalid Client Secret

`POST /oauth/token` returns 400 with:

```json
{
  "error": "invalid_client",
  "error_description": "Invalid client secret."
}
```

The client secret doesn't belong to the client ID. For the authorization code grant type, the same error appears when the form field `client_secret` is missing.

1. Open the security profile in the admin portal and copy the **Client ID** and the **Client Secret** with their copy buttons.
2. For the authorization code grant type, send `client_id`, `client_secret`, `code` and `redirect_uri` as form fields.

### The Redirect URI Doesn't Match

`GET /oauth/authorize` returns 400 with the plain text:

```text
Missing, invalid or mismatching redirection URI.
```

In an ASP.NET Core application that uses the Document Editor or Document Viewer package with a `RedirectUri`, the page shows the same text in place of the component:

```text
Authorization Error
Exception: OAuth access token request failed. Missing, invalid or mismatching redirection URI.
```

The redirect URI of the request isn't in the list **Authorized Redirect URIs** of the security profile. A profile without any redirect URI shows an alert icon in the profile list, with the tooltip `Profile has no redirect URIs defined.`

1. Copy the address of your application from the address bar of the browser, for example `https://localhost:44374`.
2. Open the security profile, click **+ Add URI** and enter the address followed by the path of the package's callback, for example `https://localhost:44374/textcontrol/documenteditor/auth/callback`. [ASP.NET Core](https://docs.textcontrol.com/ds-server/client-libraries/aspnet-core/llms-full.txt) lists the callback path of each package.
3. Click **Save** and reload the page of your application.

With a trial token on the Text Control trial server, leave out `RedirectUri`: the trial profile allows the client credentials grant type. See [Trial Token](https://docs.textcontrol.com/ds-server/getting-started/trial-token/llms-full.txt).

### The Admin Password Is Lost

The browser keeps asking for the credentials of the admin portal, and the `/admin` and `/license` endpoints of the Web API return 401 with `WWW-Authenticate: Basic realm=Access to the Admin page`.

The admin portal and these endpoints use the admin credentials with HTTP Basic authentication. After the password has been changed, only the new one works. Setting a password shorter than eight characters fails with `New password must be at least 8 characters long.`

DS Server keeps the admin password, the security profiles and the OAuth switch in the file *Admin.db* in its installation folder. Without the file, it starts like a new installation.

1. Stop DS Server.
2. Move *Admin.db* to a backup folder.
3. Start DS Server. It creates a new *Admin.db*, and the credentials are `admin` and `admin` again.
4. Change the password, create the security profiles again and enable OAuth.

All security profiles and their client credentials are lost with the old file, so every application needs new credentials. Keep the backup until the new setup works; moving it back restores the old state.

### The Log Mentions Authentication Servers

With OAuth enabled, the log of DS Server writes this line for each token that the server didn't issue itself:

```text
OAuthTokenAuthenticationService.IsAuthorized called but no authentication servers are registered.
```

The line itself is informational. DS Server can ask other DS Server instances, registered as authentication servers, whether a token is valid. Without any registered server, only the tokens it issued itself are valid, and the line reports that there is no other server to ask. The request is then refused with 401, as [Requests Return 401 Unauthorized](#requests-return-401-unauthorized) describes. [Authentication Servers](https://docs.textcontrol.com/ds-server/administration/authentication-servers/llms-full.txt) describes when to register them.

### Related Pages

- [Creating Security Profiles](https://docs.textcontrol.com/ds-server/administration/security-profiles/llms-full.txt): client ID, client secret and redirect URIs.
- [OAuth Grant Types](https://docs.textcontrol.com/ds-server/administration/oauth-grant-types/llms-full.txt): which grant type to use and the switch for client credentials.
- [OAuth](https://docs.textcontrol.com/ds-server/reference/web-api/oauth/llms-full.txt): the endpoints `/oauth/authorize` and `/oauth/token`.
- [Document Editor and Viewer](https://docs.textcontrol.com/ds-server/troubleshooting/editor-viewer/llms-full.txt): the components don't load or don't connect.
- [Installation](https://docs.textcontrol.com/ds-server/troubleshooting/installation/llms-full.txt): the server doesn't start or isn't registered.

---

## Nearby

- **Previous:** [Installation](https://docs.textcontrol.com/ds-server/troubleshooting/installation/llms-full.txt)
- **Next:** [Document Editor and Viewer](https://docs.textcontrol.com/ds-server/troubleshooting/editor-viewer/llms-full.txt)
