company_banner

OAuth 2.0 простым и понятным языком

    Логотип OAuth 2.0

    На хабре уже писали про OAuth 1.0, но понятного объяснения того, что такое OAuth 2.0 не было. Ниже я расскажу, в чем отличия и преимущества OAuth 2.0 и, как его лучше использовать на сайтах, в мобильных и desktop-приложениях.

    Что такое OAuth 2.0


    OAuth 2.0 — протокол авторизации, позволяющий выдать одному сервису (приложению) права на доступ к ресурсам пользователя на другом сервисе. Протокол избавляет от необходимости доверять приложению логин и пароль, а также позволяет выдавать ограниченный набор прав, а не все сразу.


    Чем отличаются OpenID и OAuth


    Не смотря на то, что объяснений на эту тему уже было много, она по-прежнему вызывает некоторое непонимание.

    OpenID предназначен для аутентификации — то есть для того, чтобы понять, что этот конкретный пользователь является тем, кем представляется. Например, с помощью OpenID некий сервис Ололо может понять, что зашедший туда пользователь, это именно Рома Новиков с Mail.Ru. При следующей аутентификации Ололо сможет его опять узнать и понять, что, это тот же Рома, что и в прошлый раз.

    OAuth же является протоколом авторизации, то есть позволяет выдать права на действия, которые сам Ололо сможет производить в Mail.Ru от лица Ромы. При этом Рома после авторизации может вообще не участвовать в процессе выполнения действий, например, Ололо сможет самостоятельно заливать фотографии на Ромин аккаунт.

    Как работает OAuth 2.0


    Как и первая версия, OAuth 2.0 основан на использовании базовых веб-технологий: HTTP-запросах, редиректах и т. п. Поэтому использование OAuth возможно на любой платформе с доступом к интернету и браузеру: на сайтах, в мобильных и desktop-приложениях, плагинах для браузеров…

    Ключевое отличие от OAuth 1.0 — простота. В новой версии нет громоздких схем подписи, сокращено количество запросов, необходимых для авторизации.

    Общая схема работы приложения, использующего OAuth, такова:
    1. получение авторизации
    2. обращение к защищенным ресурсам

    Результатом авторизации является access token — некий ключ (обычно просто набор символов), предъявление которого является пропуском к защищенным ресурсам. Обращение к ним в самом простом случае происходит по HTTPS с указанием в заголовках или в качестве одного из параметров полученного access token'а.

    В протоколе описано несколько вариантов авторизации, подходящих для различных ситуаций:
    • авторизация для приложений, имеющих серверную часть (чаще всего, это сайты и веб-приложения)
    • авторизация для полностью клиентских приложений (мобильные и desktop-приложения)
    • авторизация по логину и паролю
    • восстановление предыдущей авторизации


    Авторизация для приложений, имеющих серверную часть


    Схема авторизации приложений, имеющих серверную часть
    1. Редирект на страницу авторизации
    2. На странице авторизации у пользователя запрашивается подтверждение выдачи прав
    3. В случае согласия пользователя, браузер редиректится на URL, указанный при открытии страницы авторизации, с добавлением в GET-параметры специального ключа — authorization code
    4. Сервер приложения выполняет POST-запрос с полученным authorization code в качестве параметра. В результате этого запроса возвращается access token

    Это самый сложный вариант авторизации, но только он позволяет сервису однозначно установить приложение, обращающееся за авторизацией (это происходит при коммуникации между серверами на последнем шаге). Во всех остальных вариантах авторизация происходит полностью на клиенте и по понятным причинам возможна маскировка одного приложения под другое. Это стоит учитывать при внедрении OAuth-аутентификации в API сервисов.

    Пример

    Здесь и далее примеры приводятся для API Mail.Ru, но логика одинаковая для всех сервисов, меняются только адреса страниц авторизации. Обратите внимание, что запросы надо делать по HTTPS.

    Редиректим браузер пользователя на страницу авторизации:
    > GET /oauth/authorize?response_type=code&client_id=464119&
          redirect_uri=http%3A%2F%2Fexample.com%2Fcb%2F123 HTTP/1.1
    > Host: connect.mail.ru
    

    Здесь и далее, client_id и client_secret — значения, полученные при регистрации приложения на платформе.

    После того, как пользователь выдаст права, происходит редирект на указанный redirect_uri:
    < HTTP/1.1 302 Found
    < Location: http://example.com/cb/123?code=DoRieb0y
    


    Обратите внимание, если вы реализуете логин на сайте с помощью OAuth, то рекомендуется в redirect_uri добавлять уникальный для каждого пользователя идентификатор для предотвращения CSRF-атак (в примере это 123). При получении кода надо проверить, что этот идентификатор не изменился и соответствует текущему пользователю.

    Используем полученный code для получения access_token, выполняя запрос с сервера:
    > POST /oauth/token HTTP/1.1
    > Host: connect.mail.ru
    > Content-Type: application/x-www-form-urlencoded
    > 
    > grant_type=authorization_code&client_id=464119&client_secret=deadbeef&code=DoRieb0y&
      redirect_uri=http%3A%2F%2Fexample.com%2Fcb%2F123
    
    < HTTP/1.1 200 OK
    < Content-Type: application/json
    <
    < {
    <    "access_token":"SlAV32hkKG",
    <    "token_type":"bearer",
    <    "expires_in":86400,
    <    "refresh_token":"8xLOxBtZp8",
    < }
    


    Обратите внимание, что в последнем запросе используется client_secret, который в данном случае хранится на сервере приложения, и подтверждает, что запрос не подделан.

    В результате последнего запроса получаем сам ключ доступа (access_token), время его «протухания» (expires_in), тип ключа, определяющий как его надо использовать, (token_type) и refresh_token о котором будет подробнее сказано ниже. Дальше, полученные данные можно использовать для доступа к защищенным ресурсам, например, API Mail.Ru:
    > GET /platform/api?oauth_token=SlAV32hkKG&client_id=464119&format=json&method=users.getInfo&
          sig=... HTTP/1.1
    > Host: appsmail.ru
    

    Описание в спецификации

    Авторизация полностью клиентских приложений


    Схема авторизации полностью клиентских платежей
    1. Открытие встроенного браузера со страницей авторизации
    2. У пользователя запрашивается подтверждение выдачи прав
    3. В случае согласия пользователя, браузер редиректится на страницу-заглушку во фрагменте (после #) URL которой добавляется access token
    4. Приложение перехватывает редирект и получает access token из адреса страницы

    Этот вариант требует поднятия в приложении окна браузера, но не требует серверной части и дополнительного вызова сервер-сервер для обмена authorization code на access token.

    Пример

    Открываем браузер со страницей авторизации:
    > GET /oauth/authorize?response_type=token&client_id=464119 HTTP/1.1
    > Host: connect.mail.ru
    


    После того, как пользователь выдаст права, происходит редирект на стандартную страницу-заглушку, для Mail.Ru это connect.mail.ru/oauth/success.html:
    < HTTP/1.1 302 Found
    < Location: http://connect.mail.ru/oauth/success.html#access_token=FJQbwq9&token_type=bearer&
                expires_in=86400&refresh_token=yaeFa0gu
    


    Приложение должно перехватить последний редирект, получить из адреса acess_token и использовать его для обращения к защищенным ресурсам.

    Описание в спецификации

    Авторизация по логину и паролю


    Авторизация по логину и паролю представляет простой POST-запрос, в результате которого возвращается access token. Такая схема не представляет из себя ничего нового, но вставлена в стандарт для общности и рекомендуется к применению только, когда другие варианты авторизации не доступны.

    Пример

    > POST /oauth/token HTTP/1.1
    > Host: connect.mail.ru
    > Content-Type: application/x-www-form-urlencoded
    > 
    > grant_type=password&client_id=31337&client_secret=deadbeef&username=api@corp.mail.ru&
      password=qwerty
    
    < HTTP/1.1 200 OK
    < Content-Type: application/json
    <
    < {
    <    "access_token":"SlAV32hkKG",
    <    "token_type":"bearer",
    <    "expires_in":86400,
    <    "refresh_token":"8xLOxBtZp8",
    < }
    

    Описание в спецификации

    Восстановление предыдущей авторизации


    Обычно, access token имеет ограниченный срок годности. Это может быть полезно, например, если он передается по открытым каналам. Чтобы не заставлять пользователя проходить авторизацию после истечения срока действия access token'а, во всех перечисленных выше вариантах, в дополнение к access token'у может возвращаться еще refresh token. По нему можно получить access token с помощью HTTP-запроса, аналогично авторизации по логину и паролю.

    Пример

    > POST /oauth/token HTTP/1.1
    > Host: connect.mail.ru
    > Content-Type: application/x-www-form-urlencoded
    > 
    > grant_type=refresh_token&client_id=31337&client_secret=deadbeef&refresh_token=8xLOxBtZp8
    
    < HTTP/1.1 200 OK
    < Content-Type: application/json
    <
    < {
    <    "access_token":"Uu8oor1i",
    <    "token_type":"bearer",
    <    "expires_in":86400,
    <    "refresh_token":"ohWo1ohr",
    < }
    

    Описание в спецификации

    Минусы OAuth 2.0


    Во всей этой красоте есть и ложка дегтя, куда без нее?

    OAuth 2.0 — развивающийся стандарт. Это значит, что спецификация еще не устоялась и постоянно меняется, иногда довольно заметно. Так, что если вы решили поддержать стандарт прямо сейчас, приготовьтесь к тому, что его поддержку придется подпиливать по мере изменения спецификации. С другой стороны, это также значит, что вы можете поучаствовать в процессе написания стандарта и внести в него свои идеи.

    Безопасность OAuth 2.0 во многом основана на SSL. Это сильно упрощает жизнь разработчикам, но требует дополнительных вычислительных ресурсов и администрирования. Это может быть существенным вопросом в высоко нагруженных проектах.

    Заключение


    OAuth — простой стандарт авторизации, основанный на базовых принципах интернета, что делает возможным применение авторизации практически на любой платформе. Стандарт имеет поддержку крупнейших площадок и очевидно, что его популярность будет только расти. Если вы задумались об API для вашего сервиса, то авторизация с использованием OAuth 2.0 — хороший выбор.

    Со своей стороны, мы внедрили OAuth 2.0 в API Mail.Ru и, теперь, вы можете использовать возможности протокола для реализации любых клиентов и сервисов, интегрированных с Mail.Ru.

    Ссылки



    Дмитрий Битман — менеджер Платформы@Mail.Ru
    Mail.Ru Group 736,68
    Строим Интернет
    Поделиться публикацией
    Комментарии 43
    • +7
      Кроме «спасибо» и сказать особо нечего:)
      • 0
        и как его лучше использовать на сайтах

        До тех пор, пока он в статусе черновиков — его стоит использовать с осторожностью :-)
        • +1
          Однако в HTML5, который в статусе драфта все нырнули с головой :)
          • +2
            У нас для сайтов есть специальная js-обертка, которая избавляет от проблем с изменением стандарта — api.mail.ru/docs/guides/jsapi/.

            Но, в принципе, там все настолько просто, что сильно меняться оно уже вряд ли будет.
            • 0
              Тем не менее она глючит, я даже имею честь наблюдать отказ ie7 рендерить страницу вообще если на ней эта ваша обертка. Хорошо что сделали OAuth, переделаю на него
              • 0
                Мы не знали о такой проблеме. Где можно посмотреть? Поправим.
                • 0
                  Там просто нужно пару дополнительных условий, отписал в личку
            • 0
              однако ФейсБук не сильно боится, и с недавних пор его использует очень активно.
              • 0
                И фейсбук не боится, и гугл не боится. Вон и мейл не боится.

                Но фича в том, что у фейсбука он претерпел незначительные модификации. Так что вроде как это Oauth v2, а вроде как и нет :-)
            • +2
              Спасибо, очень полезно было.
              • НЛО прилетело и опубликовало эту надпись здесь
                • 0
                  дайте ответ на мой вопрос:
                  почему процесс oauth твиттера\гугла отличаются от oauth яндекса?
                  • 0
                    Разница в версиях стандарта. Твиттер и гугл используют oauth 1.0. Яндекс, Mail.Ru, Facebook и др. используют вторую версию. Вторая версия гораздо проще в реализации и понимании. Думаю, в будущем на нее перейдут все.
                    • 0
                      да, я с этим столкнулся когда писал комплексную реализацию для этих всех сервисов.
                      еще заметил что у рамблера нету oauth вобще, есть openid только.
                  • +4
                    Wow, первый «блог компании ХХХ» прочитаный с удовольствием. Good job!
                    • 0
                      Самый главный минус — это когда mail.ru закроют или продадут, придет новая метла и начнет мести по новому.

                      Один плюс — это, то что пользователю не нужно регистрироваться, он может быстро авторизоваться, под своим логином от mail.ru
                      • 0
                        Хм… как я понял всё вышеизложенное, авторизоваться может не пользователь на вашем сайте, а ваш сайт в аккаунте пользователя, то есть пользователь сообщает mail.ru, что он этому сайту разрешает делать в mail.ru от своего имени (отправлять/получать почту, например). Для быстрой аутентификации пользователя на своём сайте нужно использовать OpenID или его аналоги, а авторизацию проводить своей логикой.
                        • 0
                          *авторизацию того, что может делать пользователь на вашем сайте.
                      • 0
                        Для второго случая
                        Открытие встроенного браузера со страницей авторизации


                        Есть ли какие-нибудь препятствия для получения кода страницы авторизации через, например, курл, парсинг её, вывода пользователю, скажем, диалогового окна (или вообще хранить логин/пароль в настройках), отправки запроса через тот же курл и т. д.? Может ли это считаться «встроенным браузером» или такой вариант ничем не отличается от третьего и только лишние сложности для разработчика?

                        А вообще не понял, как собственно через API отправлять и получать письма и чем использование API лучше POP/SMTP? Ткните, пожалуйста, носом в конкретный док :)

                        • +1
                          «Встроенный браузер» в виде курла это хак системы ) Это авторизация по логину и паролю, только вместо одного запроса получается куча возни с курлом. Полноценный встроенный браузер обеспечивает несколько преимуществ:
                          * знакомый, понятный пользователю интерфейс
                          * если пользователь уже аутентифицирован на сервисе, то ему в приложении логин с паролем вводить не придется
                          * если пользователь аутентифицирован на сайте и уже авторизовывал приложение, то диалог запроса авторизации показываться не будет, будет сразу редирект с access token'ом

                          На счет API для почты. Действительно, для этого уже есть готовые стандартные протоколы, поэтому OAuth у нас реализован для «социальных» API — работы с друзьями, фотографиям, музыкой, личными сообщениями. Полный список доступных функций — api.mail.ru/docs/reference/rest/. В будущем, когда будет понятный общепринятый стандарт для интеграции OAuth с почтой, мы поддержим и его.
                          • +1
                            Первый вариант это да, отчасти — для кого-то IE это браузер, а вот webkit в контроле может быть и не понятен чем-то :)
                            Встроенный браузер, афаик, выполняется в контексте приложения и то, что пользователь находится на сайте в основном браузере никак не поможет ему, если пытается зайти через встроенный
                            Курл, по идее, должен тоже авторизоваться раз и навсегда, все что знает браузер, знает и он :)

                            Спасибо за линк, будем искать полезное. Просто как-то думал, что раз mail.ru это прежде всего почта, то и API должно прежде всего доступ к функциям почты предоставить :)
                            • 0
                              Как пользователь может быть уже авторизован на сервисе во встроенном браузере?
                              • +1
                                Да, я был не прав. Куки не шарятся между приложениями, поэтому пользователь не может быть сразу аутентифицирован, если только он не делал этого раньше в этом приложении.
                                • +1
                                  Либо можно зарегистрировать специальный протокол на ваше приложение и открывать авторизацию в стандартном браузере с соответствующим redirect_uri. Тогда магия кук сработает.
                            • 0
                              Спасибо! Как раз искал информацию об этом
                              • 0
                                А где в mail.ru интерфейс управления токенами для пользователя?
                                Если он хочет отозвать токен для какого-то приложения?
                                • 0
                                  И ещё у вас неправильный content-type при положительном ответе.
                                  Должен быть application/json, а у вас text/javascript.
                                  • 0
                                    Хотя в примере в этой статье указн application/json, но в реальности, как я описал выше ;)
                                    • +1
                                      Вот здесь — my.mail.ru/cgi-bin/connect/view
                                      • 0
                                        Промахнулся с ответом. Это был ответ на вопрос «А где в mail.ru интерфейс управления токенами для пользователя?»

                                        С content-type уточню в понедельник почему он у нас именно такой.
                                        • 0
                                          И раз уж пошёл разговор о content-type, REST API ваш отдает JSON ответы с типом text/plain.
                                          Это тоже никужа не годится.
                                          • 0
                                            text/javascript выбрали потому что в браузерах по-дефолту application/json скачивается как файл. Не удобно дебажить, разработчики жаловались. REST API поправим
                                            • 0
                                              Нифига себе не удобно :)
                                              В стандарте сказано, что content type должен быть application/json.
                                              The parameters are included in the entity body of the HTTP response
                                              using the «application/json» media type as defined by [RFC4627]. The
                                              parameters are serialized into a JSON structure by adding each
                                              parameter at the highest structure level. Parameter names and string
                                              values are included as JSON strings. Numerical values are included
                                              as JSON numbers

                                              Половина библиотек для OAuth обламываются.
                                    • 0
                                      Люди добрые, если есть силы, посоветуйте, в чем проблема у меня с аутентификацией через твиттер (ASP .NET MVC):

                                      Сначала пользователя кидаю на страницу входа через твиттер (использую consumerKey и сonsumerSecret, что получил при регистрации приложения на dev.twitter):
                                      * var tokenResponse = OAuthUtility.GetRequestToken(ConfigurationManager.ConnectionStrings[«consumerKey»].ConnectionString, ConfigurationManager.ConnectionStrings[«consumerSecret»].ConnectionString, ConfigurationManager.ConnectionStrings[«callBackUrl»].ConnectionString);
                                      * var token = tokenResponse.Token;
                                      * var url = OAuthUtility.BuildAuthorizationUri(token).AbsoluteUri;
                                      * return Redirect(url);

                                      После чего, получив oauth_token, oauth_verifier и попробуем получить accessToken:
                                      * string Oauth_Token = Request.QueryString[«oauth_token»].ToString();
                                      * string Oauth_Verifier = Request.QueryString[«oauth_verifier»].ToString();
                                      * OAuthTokenResponse accessToken = OAuthUtility.GetAccessToken(ConfigurationManager.ConnectionStrings[«consumerKey»].ConnectionString, ConfigurationManager.ConnectionStrings[«consumerSecret»].ConnectionString, Oauth_Token, Oauth_Verifier);

                                      и вот здесь засада. Раньше все работало (месяц назад). Сейчас это проходит раз из пяти попыток. Выдается сообщение что твиттер шлет 401 ошибку, и выскакивает exception.
                                      ( добавлю, что значения Oauth_Token и Oauth_Verifier приходят)

                                      Если есть идеи, напишите пожалуйста, буду очень благодарен
                                      • 0
                                        А что если при авторизации Standalone приложения я таки хочу передать redirect_uri? Сейчас это невозможно — редиректит всегда на стандартную заглушку — что неудобно в плане перехвата редиректа из системного браузера.

                                        Вот если бы можно было задать redirect_uri типа myApplicationAuth:://success было бы кул.

                                        В чем причина такого ограничения?

                                        • 0
                                          Не получается для сайта обменять code на access_token

                                          Успешно получив code делаю POST-запрос, с заголовком Content-Type: application/x-www-form-urlencoded на connect.mail.ru/oauth/token
                                          В ответ получаю {«error»:«unsupported_grant_type»}

                                          Параметры запроса у меня такие (изменены):
                                          [grant_type] => authorization_code
                                          [code] => dbef95fb3cxxxxxxdfc06661ee68ed90
                                          [client_id] => 678xxx
                                          [client_secret] => 686907143a40xxxxxxda15931dxxxxxx
                                          [redirect_uri] => site.ru
                                          т.е., все необходимые параметры передаются, почему такая ошибка если grant_type правильный?
                                          • 0
                                            Столкнулся с точно такой же проблемой при реализации oauth авторизации через Mail.ru для библиотеки com.scribe на Java. В чём была проблема?
                                            • 0
                                              нет к сожалению тогда просто отказался от авторизации через мейлру, и так и не вернулся к этой проблеме
                                          • 0
                                            А как тогда использовать OAuth для (подчёркиваю) аутентификации? Приложению необходимо связать какие-то данные с пользователем. По какому идентификатору это будет делаться?
                                            • 0
                                              OAuth не предназначен для аутентификации. Он нужен для того, чтобы ваше приложение или сайт могли от лица пользователя делать какие-то действия в гугле, мейле или еще где-нибудь, при этом, что это за пользователь вы можете и не знать.

                                              Многие системы (мэйл, фб, вк и т. п.) позволяют после авторизации запросить данные о пользователе. То есть, если через OAuth запросить авторизацию, а потом, используя API сервиса и полученную авторизацию, получить данные о пользователе, то их можно использовать для аутентификации. Но это уже надо курить API каждого конкретного сервиса и напрямую к OAuth это не относится.

                                              • 0
                                                Спасибо, я как-то так и понял по итогам чтения документации.
                                            • 0
                                              Пробую в бизнес центре подключиться к wi-fi. Мне предлагают авторизоваться через OAuth (vk, fb, twitter). Какой смысл в авторизации, если они не получают инфорацию о том, кто подключился? Или все-таки получают? Какую еще информацию они смогут выудить из моего аккаунта при авторизации? Почему OAuth, а не OpenID? Там бы я сказал, что я — zelserg без риска передачи пароля или какой другой информации о себе (телефоны, e-mail и пр).
                                              • 0
                                                Не знаю, что там у Twitter/Facebook, но у VK нет ни поддержки OpenID, ни OpenID Connect (с выдачей ID Token). Поэтому единственный вариант — получить полноценный access token и использовать методы vk api для получения информации для идентификации пользователя.

                                                Какую еще информацию они смогут выудить из моего аккаунта при авторизации?

                                                Ту, которую разработчики запросят в scope при авторизации и вы подтвердите. В случае вк, как я уже сказал, достаточно пустого scope: для доступа к информации о профиле дополнительных прав не нужно.

                                                Но никто не мешает разработчикам сервиса запросить чуть больше прав, чем необходимо. Например, чтобы постить пользователю на страницу. Это будет явно показано в момент авторизации приложения (см. scope wall), но большинство пользователей не смотрят на запрашиваемые права. А если и смотрят, то вариантов нет: или разреши спамить, или никакого тебе wifi.

                                              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                              Самое читаемое