---
title: "Use bearer tokens in client applications"
slug: "use-bearer-tokens-in-client-applications"
abstract: "Sitecore Identity provides a mechanism for Sitecore login."
---
# Use bearer tokens in client applications

This topic describes how you use bearer token authentication and the Sitecore Identity server to securely access an API from a MVC client.

Bearer token authentication involves three things:

- The Sitecore Identity (SI) server. The SI server issues access tokens in JWT (JSON Web Token) format by default. Every relevant platform today has support for validating JWT tokens. You can consider *access* and *bearer* token as the same thing.
- An API application.
- An MVC client application. The application requests an access token from the SI server and uses it to gain access to the API.

The procedures described in this topic use an example that is based on these assumptions:

- The SI server runs on `https://localhost:44356/`. Change this to your actual URL if you use the examples.
- The MVC client has `MvcClient` as ID and it is configured on the SI server in the following way:

    ```xml
    <?xml version="1.0" encoding="utf-8"?>
    <Settings>
      <Sitecore>
        <IdentityServer>
          <Clients>
            <SampleMvcClient>
              <ClientId>MvcClient</ClientId>
              <ClientName>Sample MVC client</ClientName>
              <AccessTokenType>0</AccessTokenType>
              <AllowOfflineAccess>true</AllowOfflineAccess>
              <AlwaysIncludeUserClaimsInIdToken>true</AlwaysIncludeUserClaimsInIdToken>
              <AccessTokenLifetimeInSeconds>120</AccessTokenLifetimeInSeconds>
              <IdentityTokenLifetimeInSeconds>120</IdentityTokenLifetimeInSeconds>
              <AllowAccessTokensViaBrowser>true</AllowAccessTokensViaBrowser>
              <RequireConsent>false</RequireConsent>
              <RequireClientSecret>false</RequireClientSecret>
              <AllowedGrantTypes>
                <AllowedGrantType1>client_credentials</AllowedGrantType1>
                <AllowedGrantType2>hybrid</AllowedGrantType2>
              </AllowedGrantTypes>
              <RedirectUris>
                <RedirectUri1>{AllowedCorsOrigin}/signin-oidc</RedirectUri1>
              </RedirectUris>
              <PostLogoutRedirectUris>
                <PostLogoutRedirectUri1>{AllowedCorsOrigin}/signout-callback-oidc</PostLogoutRedirectUri1>
              </PostLogoutRedirectUris>
              <AllowedCorsOrigins>
                <AllowedCorsOriginsGroup1>http://localhost:54567</AllowedCorsOriginsGroup1>
              </AllowedCorsOrigins>
              <AllowedScopes>
                <AllowedScope1>openid</AllowedScope1>
                <AllowedScope2>sitecore.profile</AllowedScope2>
                <AllowedScope3>sitecore.profile.api</AllowedScope3>
              </AllowedScopes>
              <UpdateAccessTokenClaimsOnRefresh>true</UpdateAccessTokenClaimsOnRefresh>
            </SampleMvcClient>
          </Clients>
        </IdentityServer>
      </Sitecore>
    </Settings>
    ```

This topic describes how to:

- [Protect the API](https://doc.sitecore.com/xp/en/developers/91/sitecore-experience-manager/use-bearer-tokens-in-client-applications.html#UUID-5f73ddca-743e-8f7a-c02b-8254c2cc0550_section-5c35c4dc0c8ec-idm46016444322112 "Protect the API")
- [Configure the MVC client](https://doc.sitecore.com/xp/en/developers/91/sitecore-experience-manager/use-bearer-tokens-in-client-applications.html#UUID-5f73ddca-743e-8f7a-c02b-8254c2cc0550_section-5c35e68c4329a-idm46779796924496 "Configure the MVC client")
- [Exchange refresh and access tokens](https://doc.sitecore.com/xp/en/developers/91/sitecore-experience-manager/use-bearer-tokens-in-client-applications.html#UUID-5f73ddca-743e-8f7a-c02b-8254c2cc0550_section-5c35f80a7c409-idm46533139049616 "Exchange refresh and access tokens")

## Protect the API

This section outlines the basic scenario of protecting an API, using the SI server and bearer token authentication. Protecting a ASP.NET Core-based API is only a matter of configuring the JWT bearer authentication handler in DI, and adding the authentication middleware to the pipeline.

To protect the API:

1. Use the *ASP.NET Core Web API* template to create a new project in Visual Studio, and configure the application URL in the launch profile. The example used here assumes that you configure the API with `http://localhost:55600/` as the URL. Replace this URL with the URL you actually use in your own solution.
2. Add package references to the project:

    ```xml
    <Project Sdk="Microsoft.NET.Sdk.Web">
      <PropertyGroup>
        <TargetFramework>netcoreapp2.1</TargetFramework>
      </PropertyGroup>
      <ItemGroup>
        <PackageReference Include="Microsoft.AspNetCore.App" />
      </ItemGroup>
    </Project>
    ```

3. Configure the `Startup` class:

    ```csharp
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvcCore()
                .AddAuthorization()
                .AddJsonFormatters();

            services.AddAuthentication("Bearer")
                .AddJwtBearer("Bearer", options =>
                {
                    options.Authority = "https://localhost:44356";
                    options.RequireHttpsMetadata = false;

                    options.Audience = "sitecore.profile.api";
                });
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseAuthentication();
            app.UseMvc();
        }
    }
    ```

    The `AddAuthentication` method adds the authentication services and configures `Bearer` as the default scheme. The `AddJwtBearer` method adds the SI Server access token validation handler so that the authentication services can use it. The `UseAuthentication` method adds the authentication middleware to the pipeline, so that authentication is performed automatically for every call into the host.

4. Add a new controller to your API project:

    ```csharp
    [Route("[controller]")]
    [Authorize]
    public class IdentityController : ControllerBase
    {
        [HttpGet]
        public IActionResult Get()
        {
            return new JsonResult(from c in User.Claims
                select new
                {
                    c.Type,
                    c.Value
                });
        }
    }
    ```

If you navigate to the controller (`http://localhost:55600/identity`), you get a `401` status code in return. This shows that your API requires a credential and is protected by the SI server.

## Configure the MVC client

To configure the MVC client to use the protected API:

1. Configure the application URL in the launch profile. The following example assumes that you have configured the MVC client with `http://localhost:54567/` as the URL. Replace this URL with the URL you actually use in your own solution in the `AllowedCorsOriginsGroup1` node in the SI server client configuration.
2. Add package references to the project:

    ```xml
    <Project Sdk="Microsoft.NET.Sdk.Web">
      <PropertyGroup>
        <TargetFramework>netcoreapp2.1</TargetFramework>
      </PropertyGroup>

      <ItemGroup>
        <PackageReference Include="Microsoft.AspNetCore.All" Version="[2.1.3]" />
        <PackageReference Include="Microsoft.AspNetCore.Authentication.Abstractions" Version="[2.1.1.0]" />
        <PackageReference Include="IdentityModel" Version="[3.8.0]" />
      </ItemGroup>
    </Project>
    ```

3. In the `ConfigureServices` method in the `Startup` class of the MVC application, add support for cookies and OpenID Connect authentication:

    ```csharp
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvc();

            services.AddAuthentication(options =>
                {
                    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = "oidc";
                })
                .AddCookie(options =>
                {
                    options.ExpireTimeSpan = TimeSpan.FromMinutes(60);
                    options.Cookie.Name = "mvcimplicit";
                })
                .AddOpenIdConnect("oidc", options =>
                {
                    options.ClientId = "MvcClient";
                    options.Authority = "https://localhost:44356";
                    options.RequireHttpsMetadata = false;
                    options.GetClaimsFromUserInfoEndpoint = true;
                    options.ResponseType = "code token";

                    options.Scope.Clear();
                    options.Scope.Add("openid");
                    options.Scope.Add("sitecore.profile");
                    options.Scope.Add("offline_access");
                    options.Scope.Add("sitecore.profile.api");

                    options.SaveTokens = true;

                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        NameClaimType = JwtClaimTypes.Name,
                        RoleClaimType = JwtClaimTypes.Role,
                    };
                });
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseDeveloperExceptionPage();
            app.UseStaticFiles();
            app.UseAuthentication();
            app.UseMvcWithDefaultRoute();
        }
    }
    ```

    The `AddAuthentication` method adds authentication services. A cookie is the primary way to authenticate a user because `Cookies` is specified as the *DefaultScheme*. Because the `DefaultChallengeScheme` is specified as `oidc`, when the user logs in, the OpenID Connect scheme has to be used.

    The `AddCookie` method adds the handler that can process cookies.

    The `AddOpenIdConnect` method configures the handler that performs the OpenID Connect protocol. The `Authority` property specifies that the SI server is trusted. You can identify this client with the `ClientId` property. The SignInScheme method issues a cookie, using the cookie handler, once the OpenID Connect protocol is complete. The `SaveTokens` method persists the tokens from SI server in the cookie (you need them later). Specify the `ResponseType` property as `code token` (this effectively means to use hybrid flow).

4. Call the `UseAuthentication` method in the `Configure` method to make sure that the authentication services execute for each request. You must add the authentication middleware before MVC in the pipeline.
5. To trigger the authentication handshake, add the `[Authorize]` attribute to the `Home` controller:

    ```csharp
    [Authorize]
    public class Home : Controller
    {
        private static readonly HttpClient HttpClient = new HttpClient();

        public async Task<IActionResult> Index()
        {
            string accessToken = await HttpContext.GetTokenAsync("access_token");
            string refreshToken = await HttpContext.GetTokenAsync("refresh_token");

            return Content($"Current user: <span id=\"UserIdentityName\">{User.Identity.Name ?? "anonymous"}</span><br/>" +
                $"<div>Access token: {accessToken}</div><br/>" +
                $"<div>Refresh token: {refreshToken}</div><br/>"
                , "text/html");
        }
    }
    ```

    If you now navigate to this controller in a browser, a redirect attempt is made to SI server and, if authentication is succesful, this page is shown:

    ```

    Current user: sitecore\Admin
    Access token: eyJhbG......L8A
    Refresh token: 4cdf3b4d873a65135553afdf420a47dbc898ba0c1c0ece2407bbbf2bde02a68b
    ```

6. Add this action to the `Home` controller to call the API with a bearer token:

    ```csharp
    [Route("/callapi")]
        public async Task<IActionResult> CallApi()
        {
            string accessToken = await HttpContext.GetTokenAsync("access_token");

            var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost:55600/identity");
            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
            HttpResponseMessage response = await HttpClient.SendAsync(request);

            if (response.StatusCode != HttpStatusCode.OK)
            {
                return Content(response.ToString());
            }

            return Content($"{await response.Content.ReadAsStringAsync()}");
        }
    ```

7. You obtain a bearer (access) token from the `HttpContext` with the `GetTokenAsync` method by passing the *access_token* argument. This is how you add the access token to the request header:

    ```text
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
    ```

    Navigate to `http://localhost:54567/callapi` url. The answer will be like this:

    ```csharp
    [
    {
    "type": "nbf",
    "value": "1543572239"
    },
    {
    "type": "exp",
    "value": "1543572359"
    },
    {
    "type": "iss",
    "value": "https://localhost:44356"
    },
    {
    "type": "aud",
    "value": "https://localhost:44356/resources"
    },
    {
    "type": "aud",
    "value": "sitecore.profile.api"
    },
    {
    "type": "client_id",
    "value": "MvcClient"
    },
    {
    "type": "name",
    "value": "sitecore\\Admin"
    },
    ........
    ```

You can change the calling URL (`http://localhost:55600/identity`) to call another API, for example the Sitecore item service:

```csharp
{
"ItemID": "110d559f-dea5-42ea-9c1c-8a5df7e70ef9",
"ItemName": "Home",
"ItemPath": "/sitecore/content/Home",
"ParentID": "0de95ae4-41ab-4d01-9eb0-67441b7c2450",
"TemplateID": "76036f5e-cbce-46d1-af0a-4143f9b557aa",
"TemplateName": "Sample Item",
"CloneSource": null,
"ItemLanguage": "en",
"ItemVersion": "1",
"DisplayName": "Home",
"HasChildren": "False",
"ItemIcon": "/temp/iconcache/network/16x16/home.png",
"ItemMedialUrl": "/-/icon/Network/48x48/home.png.aspx",
"ItemUrl": "~/link.aspx?_id=110D559FDEA542EA9C1C8A5DF7E70EF9&amp;amp;_z=z",
"Text": "&lt;p style.......e&lt;/a&gt;&lt;/p&gt;\r",
"Title": "Sitecore Experience Platform"
}

```

After some time (specified as the `AccessTokenLifetimeInSeconds` parameter in the client configuration on the SI server), you get a result like the following:

```csharp
StatusCode: 401, ReasonPhrase:
'Unauthorized', Version: 1.1, Content:
System.Net.Http.HttpConnection+HttpConnectionResponseContent, Headers:
{
  Server:
Kestrel

WWW-Authenticate: Bearer error="invalid_token",
error_description="The token is expired"
  X-SourceFiles:
=?UTF-8?B?Qzpcclxfd1xpc1xzYW1wbGVzXEFwaVxpZGVudGl0eQ==?=
  X-Powered-By:
ASP.NET
  Date: Fri, 30
Nov 2018 `07:42`:20 GMT

Content-Length: 0
}

```

That means the access token expired and you need to get a new one. The next section describes how to do this.

## Exchange refresh and access tokens

The SI server has a token endpoint you use to request tokens programmatically. The server supports a subset of the OpenID Connect and OAuth 2.0 token request parameters. The OpenID documentation [has a full list](https://openid.net/specs/openid-connect-core-1_0.html#TokenRequest).

To requests tokens:

1. Add the following action to the home controller:

    ```csharp
    [Route("/exchange")]
    public async Task<IActionResult> Exchange()
    {
        var disco = await DiscoveryClient.GetAsync("https://localhost:44356");
        if (disco.IsError) throw new Exception(disco.Error);

        var tokenClient = new TokenClient(disco.TokenEndpoint, "MvcClient", "secret");
        var rt = await HttpContext.GetTokenAsync("refresh_token");
        var tokenResult = await tokenClient.RequestRefreshTokenAsync(rt);

        if (!tokenResult.IsError)
        {
            var expiresAt = (DateTime.UtcNow + TimeSpan.FromSeconds(tokenResult.ExpiresIn)).ToString("o", CultureInfo.InvariantCulture);

            var authService = HttpContext.RequestServices.GetRequiredService<IAuthenticationService>();
            AuthenticateResult authenticateResult = await authService.AuthenticateAsync(HttpContext, null);
            AuthenticationProperties properties = authenticateResult.Properties;

            properties.UpdateTokenValue(OpenIdConnectParameterNames.RefreshToken, tokenResult.RefreshToken);
            properties.UpdateTokenValue(OpenIdConnectParameterNames.AccessToken, tokenResult.AccessToken);
            properties.UpdateTokenValue(OpenIdConnectParameterNames.ExpiresIn, expiresAt);

            await authService.SignInAsync(HttpContext, null, authenticateResult.Principal, authenticateResult.Properties);

            return Redirect("/");
        }

        return BadRequest();
    }
    ```

    You use an instance of the `TokenClient` class to request new tokens from the SI server. You need to have a valid refresh token before this request. After a successful request (`RequestRefreshTokenAsync`), this refresh token is invalidated and you have to update refresh and access tokens in the cookie with new ones.

2. Call the `AuthenticateAsync` method to obtain authentication properties. The `UpdateTokenValue` method updates the tokens and also the expiration timestamp in the properties, and finally the `SignInAsync` method saves the authentication cookie.

Now the `GetTokenAsync` method returns updated access or refresh tokens.