OAuth2 mail.ru provider

I want to make a authorization mail.ru but can’t find provider.
someone knows how to connect mail.ru or how to configure a different provider?
Thanks!

Hi I just responded to this question on StackOverflow, i.e. would the existing implementations of:

Help you create a one?

I would be very grateful ))

What I got:

please tell me what to write in these fields?

That’s entirely dependent on each Auth Provider, who can use whatever scopes/permissions or return whatever info they like. The scopes are used to request Users permission for data/features they want access to.

For the scopes, I don’t understand Russian, but I believe they map to permissions listed at:
http://api.mail.ru/docs/guides/restapi/#permissions

The key for the AuthMetadataProvider.ProfileUrlKey is profileUrl, which should refer to an avatar or picture url of the User (if one is returned).

It turns out if I just need the authorization of the additional permissions I don’t need, and I can Scope left empty?
If Yes, then you’re all set, thank you very much!! ))

This is the code if someone will need:

public class MailRuAuthProvider : OAuth2Provider
    {
        public const string Name = "MailRuAuth";
        public const string Realm = "https://connect.mail.ru/oauth/authorize";

        public MailRuAuthProvider(IAppSettings appSettings, string realm, string provider)
            : base(appSettings, realm, provider)
        {
            this.AuthorizeUrl = this.AuthorizeUrl ?? Realm;
            this.AccessTokenUrl = this.AccessTokenUrl ?? "https://connect.mail.ru/oauth/token";
            this.UserProfileUrl = this.UserProfileUrl ?? "https://www.appsmail.ru/platform/api";

            if (this.Scopes.Length == 0)
            {
                this.Scopes = new[] {""};
            }
        }

        protected override Dictionary<string, string> CreateAuthInfo(string accessToken)
        {
            var url = this.UserProfileUrl.AddQueryParam("access_token", accessToken);
            string json = url.GetJsonFromUrl();
            var obj = JsonObject.Parse(json);

            var authInfo = new Dictionary<string, string>
                {
                    { "user_id", obj["uid"] },
                    { "username", obj["email"] },
                    { "email", obj["email"] },
                    { "name", obj["nick"] },
                    { "first_name", obj["first_name"] },
                    { "last_name", obj["last_name"] },
                    { "gender", obj["sex"] },
                    { "birthday", obj["birthday"] },
                    { "link", obj["link"] },
                    { "picture", obj["pic"] },
                    { AuthMetadataProvider.ProfileUrlKey, obj["pic_180"] }
                };

            return authInfo;
        }
    }

Tell me please, how to enable the plugin?

You should be using the Name and Realm from your AuthProvider, e.g:

public class MailRuAuthProvider : OAuth2Provider
{
    public const string Name = "mailru";
    public const string Realm = "https://connect.mail.ru/oauth/authorize";

    public MailRuAuthProvider(IAppSettings appSettings)
        : base(appSettings, Realm, Name)
    {
        this.AuthorizeUrl = this.AuthorizeUrl ?? Realm;
        this.AccessTokenUrl = this.AccessTokenUrl ?? "https://connect.mail.ru/oauth/token";
        this.UserProfileUrl = this.UserProfileUrl ?? "https://www.appsmail.ru/platform/api";
    }

    protected override Dictionary<string, string> CreateAuthInfo(string accessToken)
    {
        var url = this.UserProfileUrl.AddQueryParam("access_token", accessToken);
        string json = url.GetJsonFromUrl();
        var obj = JsonObject.Parse(json);

        var authInfo = new Dictionary<string, string>
            {
                { "user_id", obj["uid"] },
                { "username", obj["email"] },
                { "email", obj["email"] },
                { "name", obj["nick"] },
                { "first_name", obj["first_name"] },
                { "last_name", obj["last_name"] },
                { "gender", obj["sex"] },
                { "birthday", obj["birthday"] },
                { "link", obj["link"] },
                { "picture", obj["pic"] },
                { AuthMetadataProvider.ProfileUrlKey, obj["pic_180"] }
            };

        return authInfo;
    }
}

The name is then used in the auth route, i.e. /auth/mailru - I’m using mailru instead here for naming consistency.

No worries, note this impl will also be available in the next release from this commit :slight_smile:

Yeah typically if it’s just authentication you wont need additional scopes except if their default response doesn’t include the Users email (some don’t) and you need access to their email.

:smiley: :thumbsup: very well, thanks!

1 Like

Hi Demis!

Correct provider realization don’t correct, I fixed the bugs, this is a working version, please make commit :blush:
Thanks a lot!

public class MailRuAuthProvider : OAuth2Provider {
        public const string Name = "mailru";
        public const string Realm = "https://connect.mail.ru/oauth/authorize";

        public string Method { get; private set; }
        public string Secure { get; private set; }
       
        public MailRuAuthProvider(IAppSettings appSettings)
            : base(appSettings, Realm, Name) {

            Method = appSettings.GetString("oauth.{0}.Method".Fmt(Name));
            Secure = appSettings.GetString("oauth.{0}.Secure".Fmt(Name));

            this.AuthorizeUrl = this.AuthorizeUrl ?? Realm;
            this.AccessTokenUrl = this.AccessTokenUrl ?? "https://connect.mail.ru/oauth/token";
            this.UserProfileUrl = this.UserProfileUrl ?? "https://www.appsmail.ru/platform/api";
        }

        protected override Dictionary<string, string> CreateAuthInfo(string accessToken) {
            var sig = CalcMd5("app_id={0}method={1}secure={2}session_key={3}{4}".
                Fmt(new[] { base.ConsumerKey, Method, Secure, accessToken, base.ConsumerSecret }));

            var url = this.UserProfileUrl
                .AddQueryParam("method", Method)
                .AddQueryParam("secure", Secure)
                .AddQueryParam("app_id", base.ConsumerKey)
                .AddQueryParam("session_key", accessToken)
                .AddQueryParam("sig", sig);

            var json = url.GetJsonFromUrl();

            var objList = JsonSerializer.DeserializeFromString<List<Dictionary<string, string>>>(json);

            if (objList.IsNullOrEmpty())
                return null;

            var obj = objList[0];

            var authInfo = new Dictionary<string, string>
                {
                    { "user_id", obj["uid"] },
                    { "username", obj["email"] },
                    { "email", obj["email"] },
                    { "name", obj["nick"] },
                    { "first_name", obj["first_name"] },
                    { "last_name", obj["last_name"] },
                    { "gender", obj["sex"] },
                    { "birthday", obj["birthday"] },
                    { "link", obj["link"] },
                    { "picture", obj["pic"] },
                    { AuthMetadataProvider.ProfileUrlKey, obj["pic_180"] }
                };

            return authInfo;
        }

        private string CalcMd5(string input) {
            var hashing = MD5.Create();
            return ConvertToHexString(hashing.ComputeHash(Encoding.UTF8.GetBytes(input)));
        }

        private string ConvertToHexString(IEnumerable<byte> hash) {
            var hexString = StringBuilderCache.Allocate();
            foreach (byte byteFromHash in hash) {
                hexString.Append($"{byteFromHash:x2}");
            }
            return StringBuilderCache.ReturnAndFree(hexString);
        }
    }

ok I’ve cleaned up the code a bit and updated it in this commit.

Thank you! :grinning: