<commit_before># ServiceStack.Authentication.IdentityServer

A plugin for [ServiceStack](https://servicestack.net/) and [IdentityServer](https://identityserver.github.io/) that provides [OpenIDConnect](http://openid.net/connect/) / [OAuth 2.0](http://oauth.net/2/) Single Sign-On Authentication for a Client that consumes other services (e.g. in a microservices-based environment).

This enables a client servicestack instance to be redirected to an IdentityServer instance when they attempt to access a secure service without the necessary credentials.  The user is required to provide credentials to the IdentityServer instance such that on succesful authenticated, the user is redirected back to the servicestack instance which can authorize the user to access the secure service based on claims-based credentials provided by IdentityServer.

## Quick Start
Assuming that an existing ServiceStack Instance with a user front-end exists and an existing IdentityServer Instance exists. To create a vanilla IdentityServer instance please follow the steps [here](docs/newidentityserverinstance.md).

### ServiceStack Instance
Install the package to your Service Stack Instance:
<pre>
<code>
    PM> Install-Package ServiceStack.Authentication.IdentityServer
</code>
</pre>

Add the following to your AppHost Configure method
<pre>
<code>
    public class AppHost : AppSelfHostBase
    {
        private readonly string serviceUrl;
        public AppHost(string serviceUrl) : base("ServiceStack.SelfHost", typeof (MyServices).Assembly) { this.serviceUrl = serviceUrl; }

        public override void Configure(Container container)
        {
            SetConfig(new HostConfig
            {
                // the url:port that IdentityServer will know to redirect to upon succesful login
                WebHostUrl = serviceUrl
            });

            AppSettings.SetUserAuthProvider()
                       .SetAuthRealm("http://identityserver:5000/")                 // The URL of the IdentityServer instance
                       .SetClientId("ServiceStack.SelfHost")                        // The Client Identifier so that IdentityServer can identify the service
                       .SetClientSecret("<KEY>")     // The Client Secret so that IdentityServer can authorize the service
                       .SetScopes("openid ServiceStack.SelfHost offline_access");
                       
            this.Plugins.Add(new IdentityServerAuthFeature());
        }
    }
</code>
</pre>

Decorate a service with the following attribute
<pre>
<code>
    public class SomeService : Service
    {
        [Authenticate(IdentityServerAuthProvider.Name)]
        public object Any()
        {
            ...
        }    
    }
</code>
</pre>

### IdentityServer Instance

Add the following Client to the Identity Server Client data store (example below is assuming IdentityServer In-Memory Clients is being used).
<pre>
<code>
    new Client
    {
        ClientName = "ServiceStack.SelfHost",
        ClientId = "ServiceStack.SelfHost",                                 // The Client Identifier matching the AppSettings.SetClientId() call
                                                                            // in the ServiceStack AppHost Configure() method above        
        Enabled = true,
        
        AccessTokenType = AccessTokenType.Jwt,                              // The AccessToken encryption type
        
        Flow = Flows.Hybrid,                                                // Uses the Hybrid flow

        ClientSecrets = new List&lt;Secret&gt;
        {
            new Secret("F621F470-9731-4A25-80EF-67A6F7C5F4B8".Sha256())     // The Client Secret matching AppSettings.SetClientSecret() call
        },                                                                  // in the ServiceStack Setup

        AllowAccessToAllScopes = true,                                      
        
        RedirectUris = new List&lt;string&gt;
        {
            "http://localhost:5001/auth/IdentityServer"                     // The Address and Provider Uri of the ServiceStack Instance
        },

        RequireConsent = false                                              // Don't bother prompting for consent
    }
</code>
</pre>

Add the following Scope to the Identity Server Scope data store (example below is assuming IdentityServer In-Memory Scope is being used).
<pre>
<code>
    new Scope
    {
        Name = "ServiceStack.SelfHost",                                     // The Scope Identity matching the AppSettings.SetClientId() call
                                                                            // in the ServiceStack AppHost Configure() method above        
        Enabled = true,
        
        Type = ScopeType.Identity,
        Claims = new List&lt;ScopeClaim&gt;
        {
            new ScopeClaim(Constants.ClaimTypes.Subject),
            new ScopeClaim(Constants.ClaimTypes.PreferredUserName)
        },
        ScopeSecrets = new List&lt;Secret&gt;
        {
            new Secret("F621F470-9731-4A25-80EF-67A6F7C5F4B8".Sha256())     // The Client Secret matching AppSettings.SetClientSecret() call
        }                                                                   // in the ServiceStack Setup
    }
</code>
</pre>

When you start up both the Identity Server Instance and the ServiceStack Instance, you should be redirected to the IdentityServer Instance when you try to access the service you secured with the Authenticate attribute.

## What just happened?
Assuming this worked first time for you then the following sequence of events should have occurred:

![Service Stack Identity Server Interaction](assets/ServiceStack_IdentityServer_Interaction.png)

* Attempting to access a ServiceStack Service with the Authenticate attribute forces a redirect to the IdentityServer Auth Provider (added by the *IdentityServerAuthFeature()* plugin).
* The Auth Provider checks the current ServiceStack session for an *Access Token* issued by IdentityServer.
* Having yet to be issued with an Access Token, the Auth Provider redirects the request to IdentityServer [Authorization/Authentication Endpoint](https://identityserver.github.io/Documentation/docsv2/endpoints/authorization.html).

* *Authorization/Authentication Endpoint*<commit_msg>Updating code snippets for highlighting<commit_after># ServiceStack.Authentication.IdentityServer

A plugin for [ServiceStack](https://servicestack.net/) and [IdentityServer](https://identityserver.github.io/) that provides [OpenIDConnect](http://openid.net/connect/) / [OAuth 2.0](http://oauth.net/2/) Single Sign-On Authentication for a Client that consumes other services (e.g. in a microservices-based environment).

This enables a client servicestack instance to be redirected to an IdentityServer instance when they attempt to access a secure service without the necessary credentials.  The user is required to provide credentials to the IdentityServer instance such that on succesful authenticated, the user is redirected back to the servicestack instance which can authorize the user to access the secure service based on claims-based credentials provided by IdentityServer.

## Quick Start
Assuming that an existing ServiceStack Instance with a user front-end exists and an existing IdentityServer Instance exists. To create a vanilla IdentityServer instance please follow the steps [here](docs/newidentityserverinstance.md).

### ServiceStack Instance
Install the package to your Service Stack Instance:
```powershell
PM> Install-Package ServiceStack.Authentication.IdentityServer
```

Add the following to your AppHost Configure method
```csharp
public class AppHost : AppSelfHostBase
{
    private readonly string serviceUrl;
    public AppHost(string serviceUrl) : base("ServiceStack.SelfHost", typeof (MyServices).Assembly) { this.serviceUrl = serviceUrl; }

    public override void Configure(Container container)
    {
        SetConfig(new HostConfig
        {
            // the url:port that IdentityServer will know to redirect to upon succesful login
            WebHostUrl = serviceUrl
        });

        AppSettings.SetUserAuthProvider()
                   .SetAuthRealm("http://identityserver:5000/")                 // The URL of the IdentityServer instance
                   .SetClientId("ServiceStack.SelfHost")                        // The Client Identifier so that IdentityServer can identify the service
                   .SetClientSecret("<KEY>")     // The Client Secret so that IdentityServer can authorize the service
                   .SetScopes("openid ServiceStack.SelfHost offline_access");
                       
        this.Plugins.Add(new IdentityServerAuthFeature());
    }
}
```

Decorate a service with the following attribute
```csharp
public class SomeService : Service
{
    [Authenticate(IdentityServerAuthProvider.Name)]
    public object Any()
    {
        ...
    }    
}
```

### IdentityServer Instance

Add the following Client to the Identity Server Client data store (example below is assuming IdentityServer In-Memory Clients is being used).
```csharp
new Client
{
    ClientName = "ServiceStack.SelfHost",
    ClientId = "ServiceStack.SelfHost",                                 // The Client Identifier matching the AppSettings.SetClientId() call
                                                                        // in the ServiceStack AppHost Configure() method above        
    Enabled = true,
        
    AccessTokenType = AccessTokenType.Jwt,                              // The AccessToken encryption type
        
    Flow = Flows.Hybrid,                                                // Uses the Hybrid flow

    ClientSecrets = new List&lt;Secret&gt;
    {
        new Secret("F621F470-9731-4A25-80EF-67A6F7C5F4B8".Sha256())     // The Client Secret matching AppSettings.SetClientSecret() call
    },                                                                  // in the ServiceStack Setup

    AllowAccessToAllScopes = true,                                      
    
    RedirectUris = new List&lt;string&gt;
    {
        "http://localhost:5001/auth/IdentityServer"                     // The Address and Provider Uri of the ServiceStack Instance
    },

    RequireConsent = false                                              // Don't bother prompting for consent
}
```

Add the following Scope to the Identity Server Scope data store (example below is assuming IdentityServer In-Memory Scope is being used).
```csharp
new Scope
{
    Name = "ServiceStack.SelfHost",                                     // The Scope Identity matching the AppSettings.SetClientId() call
                                                                        // in the ServiceStack AppHost Configure() method above       
    Enabled = true,
        
    Type = ScopeType.Identity,
    Claims = new List&lt;ScopeClaim&gt;
    {
        new ScopeClaim(Constants.ClaimTypes.Subject),
        new ScopeClaim(Constants.ClaimTypes.PreferredUserName)
    },
    ScopeSecrets = new List&lt;Secret&gt;
    {
        new Secret("F621F470-9731-4A25-80EF-67A6F7C5F4B8".Sha256())     // The Client Secret matching AppSettings.SetClientSecret() call
    }                                                                   // in the ServiceStack Setup
}
```

When you start up both the Identity Server Instance and the ServiceStack Instance, you should be redirected to the IdentityServer Instance when you try to access the service you secured with the Authenticate attribute.

## What just happened?
Assuming this worked first time for you then the following sequence of events should have occurred:

![Service Stack Identity Server Interaction](assets/ServiceStack_IdentityServer_Interaction.png)

* Attempting to access a ServiceStack Service with the Authenticate attribute forces a redirect to the IdentityServer Auth Provider (added by the *IdentityServerAuthFeature()* plugin).
* The Auth Provider checks the current ServiceStack session for an *Access Token* issued by IdentityServer.
* Having yet to be issued with an Access Token, the Auth Provider redirects the request to IdentityServer [Authorization/Authentication Endpoint](https://identityserver.github.io/Documentation/docsv2/endpoints/authorization.html).

* *Authorization/Authentication Endpoint*
{'fraction_non_alphanumeric': 0.06735206022828463, 'fraction_numerical': 0.010038047437869343, 'mean_word_length': 2.3443421765024364, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 27, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 40, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3970499', 'n_tokens_mistral': 2913, 'n_tokens_neox': 2785, 'n_words': 1046}