diff --git a/Owin.Security.Providers/Owin.Security.Providers.csproj b/Owin.Security.Providers/Owin.Security.Providers.csproj
index 6a1c36b..4108ac5 100644
--- a/Owin.Security.Providers/Owin.Security.Providers.csproj
+++ b/Owin.Security.Providers/Owin.Security.Providers.csproj
@@ -247,6 +247,15 @@
+
+
+
+
+
+
+
+
+
diff --git a/Owin.Security.Providers/Spotify/Constants.cs b/Owin.Security.Providers/Spotify/Constants.cs
new file mode 100644
index 0000000..8cfc92a
--- /dev/null
+++ b/Owin.Security.Providers/Spotify/Constants.cs
@@ -0,0 +1,7 @@
+namespace Owin.Security.Providers.Spotify
+{
+ internal static class Constants
+ {
+ public const string DefaultAuthenticationType = "Spotify";
+ }
+}
\ No newline at end of file
diff --git a/Owin.Security.Providers/Spotify/Provider/ISpotifyAuthenticationProvider.cs b/Owin.Security.Providers/Spotify/Provider/ISpotifyAuthenticationProvider.cs
new file mode 100644
index 0000000..46aa68f
--- /dev/null
+++ b/Owin.Security.Providers/Spotify/Provider/ISpotifyAuthenticationProvider.cs
@@ -0,0 +1,24 @@
+using System.Threading.Tasks;
+
+namespace Owin.Security.Providers.Spotify.Provider
+{
+ ///
+ /// Specifies callback methods which the invokes to enable developer control over the authentication process. />
+ ///
+ public interface ISpotifyAuthenticationProvider
+ {
+ ///
+ /// Invoked whenever Spotify succesfully authenticates a user
+ ///
+ /// Contains information about the login session as well as the user .
+ /// A representing the completed operation.
+ Task Authenticated(SpotifyAuthenticatedContext context);
+
+ ///
+ /// Invoked prior to the being saved in a local cookie and the browser being redirected to the originally requested URL.
+ ///
+ ///
+ /// A representing the completed operation.
+ Task ReturnEndpoint(SpotifyReturnEndpointContext context);
+ }
+}
\ No newline at end of file
diff --git a/Owin.Security.Providers/Spotify/Provider/SpotifyAuthenticatedContext.cs b/Owin.Security.Providers/Spotify/Provider/SpotifyAuthenticatedContext.cs
new file mode 100644
index 0000000..2be9efc
--- /dev/null
+++ b/Owin.Security.Providers/Spotify/Provider/SpotifyAuthenticatedContext.cs
@@ -0,0 +1,99 @@
+using Microsoft.Owin;
+using Microsoft.Owin.Security;
+using Microsoft.Owin.Security.Provider;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Globalization;
+using System.Security.Claims;
+
+namespace Owin.Security.Providers.Spotify.Provider
+{
+ public class SpotifyAuthenticatedContext: BaseContext
+ {
+ public SpotifyAuthenticatedContext(IOwinContext context, JObject user, string accessToken, string refreshToken, string expiresIn)
+ : base(context)
+ {
+ User = user;
+ AccessToken = accessToken;
+ RefreshToken = refreshToken;
+
+ int expiresValue;
+ if (Int32.TryParse(expiresIn, NumberStyles.Integer, CultureInfo.InvariantCulture, out expiresValue))
+ {
+ ExpiresIn = TimeSpan.FromSeconds(expiresValue);
+ }
+
+ Id = TryGetValue(user, "id");
+ Name = TryGetValue(user, "display_name");
+
+ ProfilePicture = TryGetListValue(user, "images", 0, "url");
+ }
+
+ ///
+ /// Gets the JSON-serialized user
+ ///
+ ///
+ /// Contains the Spotify user obtained from token ednpoint
+ ///
+ public JObject User { get; private set; }
+
+ ///
+ /// Gets the Spotify access token
+ ///
+ public string AccessToken { get; private set; }
+
+ ///
+ /// Gets Spotify refresh token
+ ///
+ public string RefreshToken { get; private set; }
+
+ ///
+ /// Gets Spotify access token expiration time
+ ///
+ public TimeSpan? ExpiresIn { get; set; }
+
+ ///
+ /// Gets the Spotify user ID
+ ///
+ public string Id { get; private set; }
+
+ ///
+ /// Gets the user's name
+ ///
+ public string Name { get; private set; }
+
+ ///
+ /// Gets the Spotify users profile picture
+ ///
+ public string ProfilePicture { get; private set; }
+
+ ///
+ /// Gets the representing the user
+ ///
+ public ClaimsIdentity Identity { get; set; }
+
+ ///
+ /// Gets or sets a property bag for common authentication properties
+ ///
+ public AuthenticationProperties Properties { get; set; }
+
+ private static string TryGetValue(JObject user, string propertyName)
+ {
+ JToken value;
+ return user.TryGetValue(propertyName, out value) ? value.ToString() : null;
+ }
+
+ private static string TryGetListValue(JObject user, string listPropertyName, int listPosition, string listEntryPropertyName)
+ {
+ JToken listValue;
+ bool valueExists = user.TryGetValue(listPropertyName, out listValue);
+ if (!valueExists) return null;
+ JArray list = (JArray)listValue;
+
+ if (list.Count <= listPosition) return null;
+ JToken entry = list[listPosition];
+
+ return entry.Value(listEntryPropertyName);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Owin.Security.Providers/Spotify/Provider/SpotifyAuthenticationProvider.cs b/Owin.Security.Providers/Spotify/Provider/SpotifyAuthenticationProvider.cs
new file mode 100644
index 0000000..e8cee09
--- /dev/null
+++ b/Owin.Security.Providers/Spotify/Provider/SpotifyAuthenticationProvider.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Threading.Tasks;
+
+namespace Owin.Security.Providers.Spotify.Provider
+{
+ ///
+ /// Default implementation.
+ ///
+ public class SpotifyAuthenticationProvider : ISpotifyAuthenticationProvider
+ {
+ ///
+ /// Initializes a
+ ///
+ public SpotifyAuthenticationProvider()
+ {
+ OnAuthenticated = context => Task.FromResult