Sitecore Identity Part 1

Introduction

There was a time when applications were simple and so was the application security. Things have changed with rise of internet. Software applications are not confined in a desktop, in a server or in an organization anymore. Today when we think about applications we often think about services. The service based architecture in today’s world made application security a big challenge. An application built today probably has to use multiple services, developed and hosted by different organizations or different teams within the same organization. How can application securely use services, so that proper authentication and authorization can be applied? How does security flows from application to services?

The questions I posed above are not new challenges today due to the rise of internet or service based architecture. We looked for answers for these questions when we started building browser based applications. In the simplest form, we authenticated users using form based authentication, initially custom and later on using something like, Microsoft Membership Provider or Widows Authentication. But, application itself often use other resources. A common example is using a database. In such a case, popular way is to use database connection string and provide authentication information via connection string. What if,we want to authenticate to the database using user’s original credentials (delegated authorization). That requires application to impersonate the user and it’s much harder problem to solve. In windows platform it was solved by using Kerberos authentication protocol. It is much harder to use Kerberos in service based distributed internet applications across domains, where applications/services use variety of platforms. Only common thing in service based distributed internet applications is the HTTP protocol. We needed a security protocol that uses HTTP as the communication protocol. Enter OAuth, an open protocol for authentication and authorization.

why I am not talking about Sitecore Identity Server yet? Because, I don’t want to explain things superficially. Sitecore Identity Server is built on IdentityServer4, which is a framework to build Identity Provider based on OAuth 2.0 and OpenID Connect. If we do not understand the problem in hand, we will not be able to understand why Sitecore has to create Identity Server. What’s the architectural need for future Sitecore Platform to support Authentication and Authorization this way?

Identity Problem

In the following table I tried to capture the Identity problems of modern web applications and technologies used to address the problems.

Form Authentication

The simplest way to authenticate and authorize a user is to use form based authentication, where we take the user credentials and validate it against stored information in the database or other systems like Active Directory. It is not that Form Authentication can not be secured enough, it is just that there are lot limitations when the application needs to integrate with other systems securely. Sitecore, before 9.1, used Form Authentication via Microsoft Membership Provider. In Sitecore 9.1, Sitecore removed security from the core application and created separate Identity Provider. This helps Sitecore to use same Identity Service for securing micro services, architecturally where Sitecore is heading to. You can still use Form Authentication in Sitecore 9.1 if you need to. You need to enable this config, Sitecore.Owin.Authentication.IdentityServer.Disabler.config.example, which disables the Sitecore Identity Server Provider based authentication and reset the login page to old login page.

Security Assertion Markup Language (SAML)

One of most important requirements in web based application is Single Sign-On (SSO). With SSO you can sign in once and authenticate to one or many application without logging in again. Although, it is possible to use Form Authentication with cookies to authenticate to an application once and log in to the application without logging in again as long as the cookies doesn’t expire, it only works within the same domain. You cannot use cookie across domains because of browser’s Same Origin Policy (SOP). So, you cannot SSO to more than one application that has different domain name. 
Security Assertion Markup Language (SAML) is an open standard based on XML based markup language for security assertion. SAML addresses the cross domain SSO by separating Service Provider from Identity Provider. 
Following diagram show the SAML SSO Flow. This diagram shows how SAML authenticates user using Identity Provider and use the same authentication information to log in to applications (Service Providers) across different domain.

SAML SSO Flow

OAuth

SAML addressed the SSO issue by separating Identity Provider from Service Provider. Now we can use one system to authenticate to all applications. But, in the above diagram, consider this scenario, SP1 wants to use service from SP2? How can SP1 authenticate to SP2 on behalf of user without giving SP2 user’s password? This is the Delegated Authorization problem and OAuth addresses this problem.

Let’s look at the following diagram to understand how OAuth addresses the Delegated Authorization problem.  You can log in to StackExchange using your Google account. If you choose to do that, StackExchange will connect to Google to access your Google profile and email. Although, I said log in, which is authentication, in this case authorization to get the access to the user’s Google profile indicates user has authenticated to Google successfully. This diagram shows how that communication works.

We will discover more about OAuth 2.0 communication when we will discuss about OAuth 2.0 code flow. 

OpenID Connect

OAuth 2.0 seems to address all the problem that we wanted to solve. Then, why we need OpenID Connect? To answer this, we need to understand that OAuth 2.0 is an authorization framework, it is not an authentication protocol. People started using OAuth 2.0 for authentication also and the result of that, each solution has become one of its kind. We needed a standard way to do the authentication in OAuth 2.0 authorization server. OpenId Connect is a protocol on the top of OAuth 2.0 to verify identity of end user on a authorization server.

Proof Key for Code Exchange (PKCE)

PKCE pronounce as pixy is a way to securely authorize with the authorization server without using Client Secret. What is Client Secret? In the above diagram when StackExchange connects to Google and ask for the Request Token, first it needs to identify to Google. It will provide a Client Id and Client Secret, which it already provided to Google when it registered the application with Google. Client Secret should be protected by StackExchange, otherwise, any application can claim that it is StackExchange. For the sensitive nature of the Client Secret, it is only used to authorize Web Server application. You wouldn’t use it in Javascript based application or mobile application because it can be seen or intercepted. PKCE protocol helps device or mobile app to address this problem. Since it is not needed to understand PKCE to understand OAuth, we will not explore much about it.

OAuth 2.0 Terminology

Let’s talk about some OAuth 2.0 terminology because we need to know them to understand the OAuth Code Flow (Code Flow is a terminology too).

Resource Owner

Resource Owner is really a user. In the OAuth term it is called Resource Owner because OAuth provides access to some resources to other application on behalf of the owner of the resources. For example, StackExchange is asking access to my Google profile that I own. In this case, I am the Resource Owner. 

Client

Client is an application which is asking access to the resources. In StackExchange example, StackExchange is the Client. 

Authorization Server

The Authorization Server is the system that authorize the user. The server where Client connect and asks for access to some resources. In StackExchange example, Google is the Authorization Server.

Resource Server

Resource Server is the one that contains the resources. In our StackExchange example, the Client is asking to access user’s profile. In this case profile also is stored in Google server. Resource can be something other than profile, for example, it could be documents in a folder in Google Drive. In that case Google Drive is the Resource Server.

Authorization Grant

Authorization Grant is the Resource Owner’s (user) permission to the Client to access the Resource. In the StackExchange example, when user say ‘Yes’ to Google to give access to StackExchange, user grants the permission and Google provides a authorization code to StackExchange, so that, StackExchange can get an Access Token, which it will use to access user’s profile. There are different mechanism to communicate Authorization Grant. We will discuss different grant types later.

Access Token

Client’s ultimate goal is get the Access Token. Once client has the Access Token, it can get to the Resources anytime in the Resource Server, until the Access Token expires.
In OAuth 2.0 an Access Token is just a string type. The Access Token will be validated before a resources is delivered. One way to validate an Access Token is to store the Access Token in the server and every time client sends the Access Token, resource server checks against the stored token. This is why Access Token is sometime called Reference Token. If the Access Token is a JSON Web Token (JWT), it can be both stateless and stateful. The JWT Access Token is signed, thus, it can be validated by the client. This is stateless token because token doesn’t need to be stored in the resource authorization server. JWT Access Token can also be validated against the server using OpenID Connect introspection endpoint and this is stateful Access Token. We will discuss more about Open ID Endpoints later.

Scope

Scope is a string value that is already defined in the authorization server describes granularity of resource access. Client sends the Scope to the authorization server to ask what level of resource access client needs. In the StackExchange example, it needs user’s profile access, so, the Scope can be a string value ‘profile’.  

Consent

The flip side of Scope is Consent. User gets to see the scope of access that client is asking for and grant access to specific scopes. In the StackExchange example, Google will send the profile scopes for the consent to the user and user has to give consent.

Revisit the Authorization

Now, we understand the OAuth 2.0 terminology, let’s revisit the StackExchange example one more time. Few things to notice in the following diagram.

1. StackExchange provides client_id so that Google can identify the client.
2. StackExchange tells Google what grant type (querystring response_type) to use, which is code. This means Google will exchange a code to tell StackExchange that user agreed to give access to the resources.
3. StackExchange tells Google what url (querystring redirect_uri) to use to send the authorization code by providing a callback uri.
4. StackExchange tells Google what resources it needs to access using scope (querystring scope).
5. Once user gives consent, Google sends to authorization code to StackExchange.
6. StackExchange sends the authorization code and the client secret to Google and ask for access token.
7. Google verify the client secret to verify the client and verify the authorization code and sends an access token to StackExchange with access scope included in the token.
8. StackExchange uses the access token to access resources. If StackExchange try to access anything outside to scope included in the access token, Google denies access.

Back Channel and Front Channel

We will talk about different grant types later, but we already discussed one grant type above, it is called Authorization Code grant type. Channel is the way that a grant type communicates with authorization server. If it is a server side communication, like StackExchange web server to Google authorization server, it is Back Channel communication. In the above example when StackExchange is asking for the access token by sending authorization code and client secret, that’s Back Channel communication. If the communication is only through browser, it is a Front Channel communication. In the above example, exchanging the authorization code via StackExchange callback uri is Front Channel communication. The authorization code gets transferred via query string or form post (querystring response_mode). The Back Channel communication more secured than Front Channel communication as it happens between server to server and chance of intercepting the communication is lot less.

Authentication using OpenID Connect

We briefly discussed OpenID Connect. Let’s take a look at the same StackExchange workflow if the authentication is done using OpenID Connect. As discussed before, OpenID is a thin layer on the top of OAuth 2.0, that standardized authentication using OAuth authorization server. To use OpenID Connect, both authorization server and the client has to implement OpenID Connect protocol.
The following diagram shows the Code Flow when OpenID Connect protocol is used. Flow is exactly same as the one we described in the Revisit the Authorization section, except, scope includes openid and get the id_token back. The id_token includes user’s information (we will discuss content of id_token later). Also, authorization server implements standard API endpoint /userinfo, which can be accessed using the access token to retrieve more user information if needed.

In the above discussion, I used StackExchange as an example to describe the OAuth authorization flow, in the real life StackExchange authentication and authorization using google account is lot more than what I described. The concept is not different though. Let’s look at the requests below. I used bold font so that, you can recognize them from our earlier discussion.

Request to Google:
https://accounts.google.com/o/oauth2/auth?client_id=717762328687-p17pldm5fteklla3nplbss3ai9slta0a.apps.googleusercontent.com&scope=profile+email&redirect_uri=https://stackauth.com/auth/oauth2/google&state={"sid":4,"cdl":"https://stackexchange.com/users/login-or-signup/delegated?returnurl=https%3a%2f%2fstackexchange.com%3f_%3d247192781","st":"b332ab522f5a916ec48228026c76ff3f6f249c0392328cab4563a433d0dc405b","ses":"018274bb2cd74c12a71f175403243ff8"}&response_type=codeHTTP/1.1
Callback from Google:
https://stackauth.com/auth/oauth2/google?state={"sid":4,"cdl":"https://stackexchange.com/users/login-or-signup/delegated?returnurl=https%3a%2f%2fstackexchange.com%3f_%3d247192781","st":"b332ab522f5a916ec48228026c76ff3f6f249c0392328cab4563a433d0dc405b","ses":"018274bb2cd74c12a71f175403243ff8"}&code=4/rgBAjiN72soIG0mXXOLC5tN8OOPOaNVGNeJ_M1ajoZ9GvwxxxxxQBUQtd4LP9C3v0DIZQ2-ZhMycPFOLhudH-7A&scope=email+profile+https://www.googleapis.com/auth/userinfo.email+https://www.googleapis.com/auth/userinfo.profileHTTP/1.1
StackExchange Redirects to:
https://meta.stackexchange.com/users/oauth/google?code=
4/rgBAjiN72soIG0mXXOLC5tN8OOPOaNVGNeJ_M1ajoZ9GvwxxxxxQBUQtd4LP9C3v0DIZQ2-ZhMycPFOLhudH-7A&state={"sid":4,"cdl":"https://stackexchange.com/users/login-or-signup/delegated?returnurl=https%3a%2f%2fstackexchange.com%3f_%3d247192781","st":"b332ab522f5a916ec48228026c76ff3f6f249c0392328cab4563a433d0dc405b","ses":"018274bb2cd74c12a71f175403243ff8"}&s=018274bb2cd74c12a71f175403243ff8HTTP/1.1

Things to notice in the second call that, Google changed the scope parameter to provide profile and email API. The third call, which was a redirect to another StackExchange URL, shows the authorization code. It doesn’t look like StackExchange is using OpenID Connect as I don’t see openid in the scope.

OpenID Connect Terminology

OpenID Connect is built on OAuth 2.0, so lot of the terminology discussed in OAuth 2.0 are used in OpenID Connect, but it was created for the purpose of authenticating user in authorization server. 

id_token

The id_token in OpenID Connect returns user’s information. The difference between access token and id_token is, if you want to get information about user using the access token, you have to make another call to some API endpoint. id_token saves that round trip to the server.
The id_token is a JSON Web Token (JWT). It is a JSON decoded in base 64. There are 3 parts in id_token, separated by a period (‘.’). First part is the header and it contains information like, what security algorithm is used. Second part is the payload, which contains information like, user id, token expiration time etc. Third part of the token is signature to validate if token was tampered by anyone. The client has the public key for the private key that generated the token and using that, client can validate the token.
The easiest way to decode an id_token is to use decoder in jwt.io. If you have a Sitecore 9.1 instance, go to Sitecore login screen, it will redirect you to the identity server url. Copy that url and decode it using online url decoder. Below is from my local instance. I decoded it to make it readable. I bolded the part that we already discussed and might interest you. 

https://xp910.identityserver/account/login?returnUrl=/connect/authorize/callback?client_id=Sitecore&response_mode=form_post&response_type=code id_token token&scope=openid sitecore.profile&state=OpenIdConnect.AuthenticationProperties=NIRQvgTO6YlOMQdZkYlKizcVzNV1Felc1SpP4XRYoGtM54aQ3TLipFLsPtnoMjKhbuuNYqHUgefEy4BZkuIjY43NbTPE8NWWrpTTxpQ8P8LMg2o7ZHaSCO8uXRK8A31vO1EoXz1O0RnBuha7GlnN2jjPCfYNuVNl2S4fTiNiMuVBhGPMS7FMPdSMFj0XabYWgCrTCGnxoILALWWksa5cvw&nonce=636797438206701381.MWE4OWJlNzMtZTFhYS00OWViLWE1ZWMtMGFmNzNhOWMzZWE0Mjk2NmRhZDctZDg4Yy00ZDEwLWI2MzgtY2VlMDU0YWQ1NDQx&redirect_uri=http://xp910.sitecore/identity/signin&sc_account_prefix=sitecore\&x-client-SKU=ID_NET451&x-client-ver=5.2.2.0

Now, start fiddler to capture http requests to see what response is coming back from Sitecore Identity Server once you authorize. Mine shown below. Since response_mode is form_post, idententity server is posting a form to the url that was included in the url above. You can take the id_token and copy it in the jwt.io decoder to see the header and payload information. Also, notice that the access token is a stateless JWT access token.

<form method='post' action='http://xp910.sitecore/identity/signin'><input type='hidden' name='code' value='1b6f995dc665faaffaef7db59365b8bae680a800bf7630cf612033d6fdacb512' />
<input type='hidden' name='id_token' value='eyJhbGciOiJSUzI1NiIsImtpZCI6IkE2ODVCMkFBRkU1NkFEMzQ5MDA4Nzg2NzI3NTEzMkM1QUE3ODdFNDkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJwb1d5cXY1V3JUU1FDSGhuSjFFeXhhcDRma2sifQ.eyJuYmYiOjE1NDQxNDkwNzMsImV4cCI6MTU0NDE1MjY3MywiaXNzIjoiaHR0cHM6Ly94cDkxMC5pZGVudGl0eXNlcnZlciIsImF1ZCI6IlNpdGVjb3JlIiwibm9uY2UiOiI2MzY3OTc0MzgyMDY3MDEzODEuTVdFNE9XSmxOek10WlRGaFlTMDBPV1ZpTFdFMVpXTXRNR0ZtTnpOaE9XTXpaV0UwTWprMk5tUmhaRGN0WkRnNFl5MDBaREV3TFdJMk16Z3RZMlZsTURVMFlXUTFORFF4IiwiaWF0IjoxNTQ0MTQ5MDczLCJhdF9oYXNoIjoiMHlIMW5EWENucS1udE0zUm9WemNzUSIsImNfaGFzaCI6IjZTRy10Zy1WUmJqak5rNlk3aER4TEEiLCJzaWQiOiJiNGRjNmM0ZGY1ZDI4NDQwMjhjYzNhMTdiNTUxMzc3MSIsInN1YiI6IjcwZDhkYWJiMTcwZjQ2MzBhZDRhMzQ1Nzc3Y2M0NGQ4IiwiYXV0aF90aW1lIjoxNTQ0MTQ5MDczLCJpZHAiOiJsb2NhbCIsImFtciI6WyJwd2QiXX0.hb4TgdGIeiqOqgAinEOj7Ih5fVUhb6cqgQN_7gPptvuA3hHwDCavymYvoGM3GAqxAoyNjauOZ0hTa-yrmLB-VpE2AQP9VbEqvGZTk6Y_I5lau08zijQPsrjTgsXyrfbjkzcsqDzfEyQ3igiRbYAkwwd5RxkogyxS-KQehrqBVcKkMZ1gXDqGyeJVmPmTQITN-8QgqgTneFbzjfxEFVEkCxGN6kkUki507FYwRBIFr17XMNMw44ODnBjHogydwlQMvmUcUsa_W8PcgnsHKOmtcgmNESOpJbl-_TmuP0_m3JGqehSSTQD9UU7tKFnAZJo6xJHJ81VKpFdJ2ADMat0zeA' />
<input type='hidden' name='access_token' value='eyJhbGciOiJSUzI1NiIsImtpZCI6IkE2ODVCMkFBRkU1NkFEMzQ5MDA4Nzg2NzI3NTEzMkM1QUE3ODdFNDkiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJwb1d5cXY1V3JUU1FDSGhuSjFFeXhhcDRma2sifQ.eyJuYmYiOjE1NDQxNDkwNzMsImV4cCI6MTU0NDE1MjY3MywiaXNzIjoiaHR0cHM6Ly94cDkxMC5pZGVudGl0eXNlcnZlciIsImF1ZCI6Imh0dHBzOi8veHA5MTAuaWRlbnRpdHlzZXJ2ZXIvcmVzb3VyY2VzIiwiY2xpZW50X2lkIjoiU2l0ZWNvcmUiLCJzdWIiOiI3MGQ4ZGFiYjE3MGY0NjMwYWQ0YTM0NTc3N2NjNDRkOCIsImF1dGhfdGltZSI6MTU0NDE0OTA3MywiaWRwIjoibG9jYWwiLCJzY29wZSI6WyJvcGVuaWQiLCJzaXRlY29yZS5wcm9maWxlIl0sImFtciI6WyJwd2QiXX0.AVcpOYq0OflaPwHKfmgi67Y1ReK9k2kybpyzQxd8J7fIC97Zk0SNUKEEjL5OVQjt9NhkzL7jR37V9TrNAW4X3hnpTn0qTP8VMK8phUdLNt8nEe2YTg0g-Wqq2xbRSENT5VRQdt5L7HaYQVmtOP8A-UbrZ3VUm2jAdxS1gLqJiB3N4WJHvUet3I4gXrNEdmaqQmFwdoe5KpxgDeFRt6nfyRYPAPJMiKbS23G6d1fDXhrBrIRlmYb4JzepNxpvWMf2HQbNrZ3m-oQ7qwbUDNoOpYfvt_Rf7n3EOvSSUyA8z7n9TEyG4mB4rse-91nfyUhbNR46wRThuyOGpj8Ah6YO0g' />
<input type='hidden' name='token_type' value='Bearer' />
<input type='hidden' name='expires_in' value='3600' />
<input type='hidden' name='scope' value='openid sitecore.profile' />
<input type='hidden' name='state' value='OpenIdConnect.AuthenticationProperties=NIRQvgTO6YlOMQdZkYlKizcVzNV1Felc1SpP4XRYoGtM54aQ3TLipFLsPtnoMjKhbuuNYqHUgefEy4BZkuIjY43NbTPE8NWWrpTTxpQ8P8LMg2o7ZHaSCO8uXRK8A31vO1EoXz1O0RnBuha7GlnN2jjPCfYNuVNl2S4fTiNiMuVBhGPMS7FMPdSMFj0XabYWgCrTCGnxoILALWWksa5cvw' />
<input type='hidden' name='session_state' value='MOXMSSjr5T1vZfYiECHizTqOiS_hmqvDuJ-tyDo1C6s.4b49bd60437e81b5ccaf94d2d9acb3ba' />
</form>

Here is the decoded id_token from jwt.io

Endpoints

OpenID Connect standardized the REST EndPoints exposed by the authorization server. Each endpoint a has purpose to accomplish authentication. Following are different endpoints:

Discovery Endpoint
Purpose of Discovery Endpoint is to provide authorization server metadata. Using Discovery Endpoint we can find other endpoints. The Endpoint url is https://xp910.identityserver/.well-known/openid-configuration where https://xp910.identityserver is my Sitecore Identity Server root. You should check the Discovery Endpoint to understand what configurations are supported by the Sitecore authorization server. In fact, what other endpoints are available, can be found in the metadata returned by the Discovery Endpoint. Below is the response from Discovery endpoint in my Sitecore Identity server.

{
  "issuer": "https://xp910.identityserver",
  "jwks_uri": "https://xp910.identityserver/.well-known/openid-configuration/jwks",
  "authorization_endpoint": "https://xp910.identityserver/connect/authorize",
  "token_endpoint": "https://xp910.identityserver/connect/token",
  "userinfo_endpoint": "https://xp910.identityserver/connect/userinfo",
  "end_session_endpoint": "https://xp910.identityserver/connect/endsession",
  "check_session_iframe": "https://xp910.identityserver/connect/checksession",
  "revocation_endpoint": "https://xp910.identityserver/connect/revocation",
  "introspection_endpoint": "https://xp910.identityserver/connect/introspect",
  "frontchannel_logout_supported": true,
  "frontchannel_logout_session_supported": true,
  "backchannel_logout_supported": true,
  "backchannel_logout_session_supported": true,
  "scopes_supported": [
    "openid",
    "profile",
    "email",
    "sitecore.profile",
    "sitecore.profile.api",
    "offline_access"
  ],
  "claims_supported": [
    "sub",
    "name",
    "family_name",
    "given_name",
    "middle_name",
    "nickname",
    "preferred_username",
    "profile",
    "picture",
    "website",
    "gender",
    "birthdate",
    "zoneinfo",
    "locale",
    "updated_at",
    "email",
    "email_verified",
    "role",
    "http://www.sitecore.net/identity/claims/isAdmin",
    "http://www.sitecore.net/identity/claims/originalIssuer"
  ],
  "grant_types_supported": [
    "authorization_code",
    "client_credentials",
    "refresh_token",
    "implicit",
    "password"
  ],
  "response_types_supported": [
    "code",
    "token",
    "id_token",
    "id_token token",
    "code id_token",
    "code token",
    "code id_token token"
  ],
  "response_modes_supported": [
    "form_post",
    "query",
    "fragment"
  ],
  "token_endpoint_auth_methods_supported": [
    "client_secret_basic",
    "client_secret_post",
    "private_key_jwt"
  ],
  "subject_types_supported": [
    "public"
  ],
  "id_token_signing_alg_values_supported": [
    "RS256"
  ],
  "code_challenge_methods_supported": [
    "plain",
    "S256"
  ]
}

Authorize Endpoint
Authorize Endpoint is used specifically to authenticate the user in OpenID Connect. It can return authorization code as well as token. Since this endpoint can return token also, it is used in the hybrid grant type (discussed later) and additional round trip to server is not needed to get token separately. Authorization Endpoint url is
https://xp910.identityserver/connect/authorize.

Token Endpoint
Token Endpoint is used to get access token or id_token from the authorization server. You have to provide some credentials like, Authorization Code, Client Credential etc. to get the token. The Token Endpoint url is 
https://xp910.identityserver/connect/token

Userinfo Endpoint
Purpose of Userinfo Endpoint is to return additional information about the logged in user. You have to pass Access Token to call Userinfor Endpoint. The Userinfo Endpoint url is https://xp910.identityserver/connect/userinfo.

Endsession Endpoint
Purpose of Endsession Endpoint is to end user’s session for selected application. For example, say, there are multiple clients that are authorized by user to the Sitcore Identity Server, using Endsession Endpoint user’s browser session can be ended for all the clients. The Endsession Endpoint url is
https://xp910.identityserver/connect/endsession.

Check Session Iframe Endpoint
Purpose of this endpoint is to check user’s session status using cross-origin communication via HTML5 postmessage API. Identity server accepts the postmessage and return the login status of the user’s session. 
The Check Session Iframe Endpoint url is
https://xp910.identityserver/connect/checksession.

Revocation Endpoint
This endpoint allows revoking the access token and refresh token from the Identity Server. The Revocation Endpoint url is
https://xp910.identityserver/connect/revocation.

Introspection Endpoint
This endpoint is used to validate reference tokens in the server. As discussed before tokens can be stateful or stateless. The JWT tokens are stateless and can be validated using signature, but stateful reference tokens which don’t have signatures can be checked only by making API call to the Introspection Endpoint. The Introspection Endpoint url is https://xp910.identityserver/connect/introspect.

Grant Types

Grant types are different ways to authorize user. Sitecore Identity Server supports following OAuth 2.0 grant types plus Hybrid grant types.

Sitecore Identity Server Grant Types

Authorization Code
We discussed Authorization Code Flow before. This is a grant type to get token  using the Back Channel. Client gets the Authorization Code and exchange that to get id_token or access token. When this grant type is used all tokens come from the token endpoint. 

Client Credentials
This grant type is used for authenticating a client in server to server communication. Client provides it’s Client Id and Client Secret to authenticate via token endpoint.

Password
This grant type uses resource owner’s username and password for authentication via token endpoint. This mostly used in legacy application and it is not recommended. 

Implicit
Implicit grant type is mainly designed to use from browser based application using scripting language like javascript. Implicit flow doesn’t use token endpoint; all tokens are returned from authorize endpoint. In this flow no client authentication is done by the authorization server. Authorization server authenticates the end user (resource owner), gets the consent and redirect the end user back to the client with id token and access token. Client validates the tokens using signature to make sure the token was not altered. Since all communication are done through front channel, this grant type doesn’t allow accessing token using refresh token due to the security concern.

Hybrid
Hybrid authorization is combination of implicit flow and code authorization flow. When this flow is used authorization server uses authorize endpoint via front channel and redirect end user to client with authorization code and id token. Client validates the id token using signature and requests access token using token endpoint via back channel. Since the access token retrieval is done via back channel, authorization server can provide refresh token to be used later to get access token in the offline mode.

Refresh Token
Refresh Token flow was designed to get access token non-interactively when access token is expired. This helps us to avoid asking for client consent every time the access token expires. It is also helpful when client is running a background process  on end user’s behalf  and there is no way to interact with the end user when access token expired. To enable refresh token flow client needs to include offline_access scope.

Claims

Claims is a way to define what end user information will be communicated by OpenID Provider (OP). Claims are communicated via id token or via userinfo endpoint. There are standard Claims defined in OpenID Connect protocol, but additional Claims can be added. Below is the list of Claims available in Siecore Identity server.

Sitecore Identity Server Claims

Scopes

OpenID Connect uses OAuth 2.0 Scopes. It has standardized the Scopes for the protocol. Scopes must include “openid”. Additionally, some optional Scopes can be included, for example, “profile”, “email” etc. For OpenID Connect, scopes can be used to request that specific sets of information be made available as Claim Values. Also, if you want to get the Refresh Token, “offline_access” scope has to be included. Below are Scopes supported in Sitecore Identity server. 

Sitecore Identity Server Scopes

Response Types

Response types defines what response to be sent back from the OpenID Connect Provider (OP). If the request url response_type=code, OP will only return authorization code. In our example above, we found that Sitecore Identity Server url contains response_type=code id_token token. When Sitecore Identity Server gets user consent, it posts all of them to the client redirect url. Following are different Response Types supported by Sitecore Identity Server.

Sitecore Identity Server Response Types

Response Modes

Response Modes define how the responses should be sent to client. Response can be sent as form post, query string or fragment in the redirect URI. If query is used as the mode, care should be taken to make sure length doesn’t exceed url length limit. All Response Modes supported in Sitecore Identity Server.

Sitecore Identity Server Response Modes

Token Validation

Tokens returned by Sitecore Identity server are jwt token. The signature of that can be verified using the public key of the private key that signed the tokens. How to validate the signature?
The discovery endpoint provides the JSON Web Key Set (JWKS) URI endpoint https://xp910.identityserver/.well-known/openid-configuration/jwks.&nbsp;Using the jwt.io libraries the public key can be extracted to verify the signature.
Go to this site https://8gwifi.org/jwkconvertfunctions.jsp to convert JWK to PEM. You need to only use kty, n, e from JWK. Insert the public key in jwt.io
to verify the signature.
I described above method to validate the token signature to tell you how OpenID Connect protocol standardized signature validation. In Sitecore Identity Server, IdentityServer4 framework validates the signature when token is returned to the client.

Role of Sitecore Identity Server in Sitecore Micro Service Architecture

So far we have discussed important OAuth 2.0 and OpenID Connect concepts used in Sitecore Identity server. Let’s discuss why Sitecore created the Sitecore Identity Server and how it fits in Sitecore’s future micro service based architecture. In the following diagram, I tried to explain how Sitecore Identity Provider fits into the future Sitecore micro services architecture. The micro services shown in Sitecore XP are my guess and in reality they will be probably vastly different. The part that I am sure about is the layers above the micro services. Every service will be authorized via Sitecore Identity Provider and it will serve both front channel and back channel communication. Currently, Sitecore Commerce has it’s own Identity Provider, I am guessing Sitecore Identity will serve both Sitecore and Sitecore Commerce.

End of Part 1

This blog post is already too long. I think, it is right time to stop. In this blog post, we discussed about OAuth 2.0 and OpenID Connect concepts. We discussed how those concepts are used in Sitecore Identity Server. We also looked at the need for Sitecore Identity Server from overall Sitecore Micro Service Architecture point of view.
In the next part we will explore how we can use Sitecore Identity Server to authenticate an application that intend to use Sitecore services. We will also explore how Sitecore Identity Server can be connected to external Identity Provider.

References

Advertisements

About Himadri Chakrabarti

I am a solutions architect and a Sitecore MVP. I am focused on Sitecore and Ecommerce development. Opinions expressed in my blogs are my own.
This entry was posted in sitecore Identity and tagged , , , , . Bookmark the permalink.

1 Response to Sitecore Identity Part 1

  1. Pingback: Sitecore Identity Part 2: Identity Client and Resource Authorization | Himadri's Technical Blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.