В общем это мой первый код,столкнулся с проблемой,что на сайте где мне нужна авторизация есть csrf токен
Строка в HTML выглядит так:
<meta name="csrf-token" content="LEHb0gOOweqUBc6dBfMmqAW5VN9y9tTXEep1AGIhsL1OMYyfQvqtvtlu-MdKhm3nbcktiiagnockvgBjGm3jzw==">
мне нужно эту строку с токеном найти в моем коде и вставить
import requests
from bs4 import BeautifulSoup
file = open('1.txt').read().split('n')
url = 'https://fastmoney.ru/auth/login'
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36'}
session = requests.Session()
session.headers.update(headers)
r = session.get(url)
soup = BeautifulSoup(r.content, 'html.parser')
csrf = soup.find('meta', {'name': 'csrf-token'})['content']
for account in file:
username = account.split(":")[0]
password = account.split(":")[1]
resp = requests.post(url, data = {'_csrf': csrf, 'LoginForm[login]': username, 'LoginForm[password]': password,})
Первый раз занимаюсь этим,поэтому не бейте сильно.Думаю для знающих будет очень просто помочь мне)
Про токены, JSON Web Tokens (JWT), аутентификацию и авторизацию. Token-Based Authentication
Last major update: 25.08.2020
- Что такое авторизация/аутентификация
- Где хранить токены
- Как ставить куки ?
- Процесс логина
- Процесс рефреш токенов
- Кража токенов/Механизм контроля токенов
- Зачем все это ? JWT vs Cookie sessions
Основа:
Аутентификация(authentication, от греч. αὐθεντικός [authentikos] – реальный, подлинный; от αὐθέντης [authentes] – автор) – это процесс проверки учётных данных пользователя (логин/пароль). Проверка подлинности пользователя путём сравнения введённого им логина/пароля с данными сохранёнными в базе данных.
Авторизация(authorization — разрешение, уполномочивание) – это проверка прав пользователя на доступ к определенным ресурсам.
Например, после аутентификации юзер sasha получает право обращаться и получать от ресурса “super.com/vip” некие данные. Во время обращения юзера sasha к ресурсу vip система авторизации проверит имеет ли право юзер обращаться к этому ресурсу (проще говоря переходить по неким разрешенным ссылкам)
- Юзер c емайлом sasha_gmail.com успешно прошел аутентификацию
- Сервер посмотрел в БД какая роль у юзера
- Сервер сгенерил юзеру токен с указанной ролью
- Юзер заходит на некий ресурс используя полученный токен
- Сервер смотрит на права(роль) юзера в токене и соответственно пропускает или отсекает запрос
Собственно п.5 и есть процесс авторизации.
Дабы не путаться с понятиями Authentication/Authorization можно использовать псевдонимы checkPassword/checkAccess(я так сделал в своей API)
JSON Web Token (JWT) — содержит три блока, разделенных точками: заголовок(header), набор полей (payload) и сигнатуру. Первые два блока представлены в JSON-формате и дополнительно закодированы в формат base64. Набор полей содержит произвольные пары имя/значения, притом стандарт JWT определяет несколько зарезервированных имен (iss, aud, exp и другие). Сигнатура может генерироваться при помощи и симметричных алгоритмов шифрования, и асимметричных. Кроме того, существует отдельный стандарт, отписывающий формат зашифрованного JWT-токена.
Пример подписанного JWT токена (после декодирования 1 и 2 блоков):
{ alg: "HS256", typ: "JWT" }.{ iss: "auth.myservice.com", aud: "myservice.com", exp: 1435937883, userName: "John Smith", userRole: "Admin" }.S9Zs/8/uEGGTVVtLggFTizCsMtwOJnRhjaQ2BMUQhcY
Токены предоставляют собой средство авторизации для каждого запроса от клиента к серверу. Токены(и соответственно сигнатура токена) генерируются на сервере основываясь на секретном ключе(который хранится на сервере) и payload’e. Токен в итоге хранится на клиенте и используется при необходимости авторизации какого-либо запроса. Такое решение отлично подходит при разработке SPA.
При попытке хакером подменить данные в header’ре или payload’е, токен станет не валидным, поскольку сигнатура не будет соответствовать изначальным значениям. А возможность сгенерировать новую сигнатуру у хакера отсутствует, поскольку секретный ключ для зашифровки лежит на сервере.
access token – используется для авторизации запросов и хранения дополнительной информации о пользователе (аля user_id, user_role или еще что либо, эту информацию также называет payload). Все поля в payload это свободный набор полей необходимый для реализации вашей частной бизнес логики. То бишь user_id и user_role не являются требованием и представляют собой исключительно частный случай. Сам токен храним не в localStorage как это обычно делают, а в памяти клиентского приложения.
refresh token – выдается сервером по результам успешной аутентификации и используется для получения новой пары access/refresh токенов. Храним исключительно в httpOnly куке.
Каждый токен имеет свой срок жизни, например access: 30 мин, refresh: 60 дней
Поскольку токены(а данном случае access) это не зашифрованная информация крайне не рекомендуется хранить в них какую либо sensitive data
(passwords, payment credentials, etc…)
Роль рефреш токенов и зачем их хранить в БД. Рефреш на сервере хранится для учета доступа и инвалидации краденых токенов. Таким образом сервер наверняка знает о клиентах которым стоит доверять(кому позволено авторизоваться). Если не хранить рефреш токен в БД то велика вероятность того что токены будут бесконтрольно гулять по рукам злоумышленников. Для отслеживания которых нам придется заводить черный список и периодически чистить его от просроченных. В место этого мы храним лимитированный список белых токенов для каждого юзера отдельно и в случае кражи у нас уже есть механизм противодействия(описано ниже).
Как ставить куки ?
Для того что бы refreshToken
кука была успешно уставленна и отправлена браузером, адреса эндпоинтов аутентификации(/api/auth/login
, /api/auth/refresh-tokens
, /api/auth/logout
) должны располагася в доменном пространстве сайта. Тоесть для домена super.com
на сервере ставим куку с такими опциями:
{
domain: '.super.com',
path: '/api/auth'
}
Таким образом кука установится в браузер и прийдет на все эндпоинты по адресу super.com/api/auth/<any-path>
Если у нас монолит и за аутентификацию отвечает один и тот-же API, тут проблем не должно быть. Но если за аутентификацию отвечает отдельный микросервис, прячем его средствами nginx
по выше указанному пути (super.com/api/auth
).
# пример настройки nginx конфига(только основые настройки)
server {
listen 80;
server_name super.com;
# SPA/Front-end
location / {
try_files $uri /index.html;
root /var/www/frontend/dist;
index index.html;
}
# Main API
location /api {
proxy_pass http://111.111.111.111:7000;
}
# Auth API
location /api/auth {
proxy_redirect http://222.222.222.222:7000 /auth/;
proxy_pass http://222.222.222.222:7000;
}
}
Логин, создание сессии/токенов (api/auth/login):
- Пользователь логинится в приложении, передавая логин/пароль и fingerprint браузера (ну или некий иной уникальный идентификатор устройства если это не браузер)
- Сервер проверят подлинность логина/пароля
- В случае удачи создает и записывает сессию в БД
{ userId: uuid, refreshToken: uuid, expiresIn: int, fingerprint: string, ... }
(схема таблицы ниже) - Создает access token
- Отправляет клиенту access и refresh token uuid (взятый из выше созданной сессии)
Set-Cookie: refreshToken='c84f18a2-c6c7-4850-be15-93f9cbaef3b3'; HttpOnly // для браузера
{
body: {
accessToken: 'eyJhbGciOiJIUzUxMiIsI...',
refreshToken: 'c84f18a2-c6c7-4850-be15-93f9cbaef3b3' // для мобильных приложений
}
}
- Клиент сохраняет токены(access в памяти приложения, refresh сетится как кука автоматом)
На что нужно обратить внимание при установке refresh куки:
maxAge
куки ставим равнуюexpiresIn
из выше созданной сессии- В
path
ставим корневой роутauth
контроллера (/api/auth
) это важно, таким образом токен получат только те хендлеры которым он нужен(/api/auth/logout
и/api/auth/rerfesh-tokens
), остальные обойдутся(нечего зря почём отправлять sensitive data).
Стоит заметить, что процесс добавления сессии в таблицу должен имеет свои меры безопасности. При добавлении стоит проверять сколько рефреш-сессий всего есть у юзера и, если их слишком много или юзер конектится одновременно из нескольких подсетей, стоит предпринять меры. Имплементируя данную проверку, я проверяю только что бы юзер имел максимум до 5 одновременных рефреш-сессий максимум, и при попытке установить следующую удаляю предыдущие. Все остальные проверки на ваше усмотрение в зависимости от задачи.
Таким образом если юзер залогинился на пяти устройствах, рефреш токены будут постоянно обновляться и все счастливы. Но если с аккаунтом юзера начнут производить подозрительные действия(попытаются залогинится более чем на 5’ти устройствах) система сбросит все сессии(рефреш токены) кроме последней.
Перед каждым запросом клиент предварительно проверяет время жизни access token’а (да берем expiresIn
прямо из JWT в клиентском приложении) и если оно истекло шлет запрос на обновление токенов. Для большей уверенности можем обновлять токены на несколько секунд раньше. То есть кейс когда API получит истекший access токен практически исключен.
Что такое fingerprint ? Это инструмент отслеживания браузера вне зависимости от желания пользователя быть идентифицированным. Это хеш сгенерированный js’ом на базе неких уникальных параметров/компонентов браузера. Преимущество fingerprint’a в том что он нигде персистентно не хранится и генерируется только в момент логина и рефреша.
- Библиотека для хеширования: https://github.com/Valve/fingerprintjs2
- Более подробно: https://player.vimeo.com/video/151208427
- Пример ф-ции получения такого хеша: https://gist.github.com/zmts/b26ba9a61aa0b93126fc6979e7338ca3
В случае если клиент не браузер, а мобильное приложение, в качестве fingerprint используем любую уникальную строку(тот же uuid
) персистентно хранящуюся на устройстве.
Рефреш токенов (api/auth/refresh-tokens):
Для использования возможности аутентификации на более чем одном девайсе необходимо хранить все рефреш токены по каждому юзеру. Я храню это список в PostgreSQL таблице(а надо бы в Redis’е). В процессе каждого логина создается запись с IP/Fingerprint и другой мета информацией, так званая рефреш-сессия.
CREATE TABLE refreshSessions (
"id" SERIAL PRIMARY KEY,
"userId" uuid REFERENCES users(id) ON DELETE CASCADE,
"refreshToken" uuid NOT NULL,
"ua" character varying(200) NOT NULL, /* user-agent */
"fingerprint" character varying(200) NOT NULL,
"ip" character varying(15) NOT NULL,
"expiresIn" bigint NOT NULL,
"createdAt" timestamp with time zone NOT NULL DEFAULT now()
);
- Клиент(фронтенд) проверяет перед запросом не истекло ли время жизни access token’на
- Если истекло клиент делает запрос на
POST auth/refresh-tokens
{ fingerprint: string }
вbody
и соответственноrefreshToken
куку. - Сервер получает запись рефреш-сессии по UUID’у рефреш токена
- Сохраняет текущую рефреш-сессию в переменную и удаляет ее из таблицы
- Проверяет текущую рефреш-сессию:
- Не истекло ли время жизни
- На соответствие старого fingerprint’a полученного из текущей рефреш-сессии с новым полученным из тела запроса
- В случае негативного результата бросает ошибку
TOKEN_EXPIRED
/INVALID_REFRESH_SESSION
- В случае успеха создает новую рефреш-сессию и записывает ее в БД
- Создает access token
- Отправляет клиенту access и refresh token uuid (взятый из выше созданной рефреш-сессии)
Set-Cookie: refreshToken='c84f18a2-c6c7-4850-be15-93f9cbaef3b3'; HttpOnly // для браузера
{
body: {
accessToken: 'eyJhbGciOiJIUzUxMiIsI...',
refreshToken: 'c84f18a2-c6c7-4850-be15-93f9cbaef3b3' // для мобильных приложений
}
}
Tip: Для отправки запроса с куками для axios
есть опция { withCredentials: true }
Ключевой момент:
В момент рефреша то есть обновления access token’a обновляются ОБА токена. Но как же refresh token может сам себя обновить, он ведь создается только после успешной аутентификации ? refresh token в момент рефреша сравнивает себя с тем refresh token’ом который лежит в БД и вслучае успеха, а также если у него не истек срок, система рефрешит токены.
Вопрос зачем refresh token’y срок жизни, если он обновляется каждый раз при обновлении access token’a ? Это сделано на случай, если юзер будет в офлайне более 60 дней, тогда придется заново вбить логин/пароль.
В случае кражи access токена и refresh куки:
- Хакер воспользовался access token’ом
- Закончилось время жизни access token’на
- Клиент хакера отправляет refresh token и fingerprint
- Сервер смотрит fingerprint хакера
- Сервер не находит fingerprint хакера в рефреш-сессии и удаляет ее из БД
- Сервер логирует попытку несанкционированного обновления токенов
- Сервер перенаправляет хакера на станицу логина. Хакер идет лесом
- Юзер пробует зайти на сервер >> обнаруживается что refresh token отсутствует
- Сервер перенаправляет юзера на форму аутентификации
- Юзер вводит логин/пароль
В случае кражи access токена, refresh куки и fingerprint’а:
Стащить все авторизационные данные это не из легких задач, но все же допустим этот кейс как крайний и наиболее неудобный с точки зрения UX (без примера в кодовой базе supra-api-nodejs
).
Предложу несколько вариантов решения данной проблемы:
- Хранить IP или Subnet залогиненного клиента
- Хакер воспользовался access token’ом
- Закончилось время жизни access token’на
- Хакер отправляет refresh куку и fingerprint
- Сервер проверяет IP хакера, хакер идет лесом
UX минус: нужно логинится с каждого нового IP.
- Удалять все сессии в случае если refresh токен не найден
- Хакер воспользовался access token’ом
- Закончилось время жизни access token’на
- Хакер отправляет refresh куку и fingerprint
- На сервере создается новый refresh токен (“от хакера”)
- Хакер получает новую пару токенов
- Юзер пробует отправить запрос на сервер >> обнаруживается что refresh токен не валиден
- Сервер удаляет все сессии юзера, в последствии чего хакер больше не сможет обновлять access токен
- Сервер создает новую сессию для пользователя
UX минус: в каждом случае когда сервер не будет находить рефреш токен – будут сбрасиватся все сессии юзера на всех устройствах.
Зачем все это ? JWT vs Cookie sessions
Зачем этот весь геморой ? Почему не юзать старые добрые cookie sessions ? Чем не угодили куки ?
- Куки подвержены CSRF: https://habr.com/ru/company/oleg-bunin/blog/412855 https://www.youtube.com/watch?v=x5AuK_IbJlg
- Нативыным приложениям для сматфонов удобнее работать с токенами. Да есть хаки для работы с куки, но это не нативная поддержка
- Куки в микросерисной архитектуре использовать не вариант. Напомню зачастую микросервисы раскиданы на разных доменах, а куки не поддерживают кросc-доменные запросы
- В микросерисной архитектуре JWT позволяет каждому сервису независимо от сервера авторизации верифицировать
access
токен (через публичный ключ) - При использовании cookie sessions программист зачастую надеется на то, что предоставил фреймворк и оставляет как есть
- При использовании jwt мы видим проблему с безопасностью и стараемся предусмотреть механизмы контроля в случае каржи авторизационных данных. При использовании cookie сессий программист зачастую даже не задумывается что сессия может быть скомпрометирована
- На каждом запросе использование JWT избавляет бекенд от одного запроса в БД(или кеш) за данными пользователя(
userId
,email
, etc.)
В итоге:
- access токены храним исключительно в памяти клиентского приложения. Не в глобально доступной переменной аля
window.accessToken
а в замыкании - refresh токен храним исключительно в httpOnly куке
- Механизмы контроля при угоне sensitive data в наличии
- Взяли лучшее из обеих технологий, максимально обезопасились от CSRF/XSS
- Добавьте в компанию ко всему CSP заголовки и SameSite=Strict флаг для кук и ждите прихода злодеев
p.s. Каждой задаче свой подход. Юзайте в небольших/средних монолитах cookie sessions
и не парьтесь. Ну или на ваш вкус 🙂
Имплементация:
Front-end:
- https://github.com/zmts/beauty-vuejs-boilerplate/blob/master/src/services/http.init.js
- https://github.com/zmts/beauty-vuejs-boilerplate/blob/master/src/services/auth.service.js
Back-end:
- https://github.com/zmts/supra-api-nodejs/tree/master/modules/auth
Info:
- https://www.youtube.com/playlist?list=PLvTBThJr861y60LQrUGpJNPu3Nt2EeQsP
- https://habrahabr.ru/company/Voximplant/blog/323160/
- https://tools.ietf.org/html/rfc6749
- https://www.digitalocean.com/community/tutorials/oauth-2-ru
- https://jwt.io/introduction/
- https://auth0.com/blog/using-json-web-tokens-as-api-keys/
- https://auth0.com/blog/cookies-vs-tokens-definitive-guide/
- https://auth0.com/blog/ten-things-you-should-know-about-tokens-and-cookies/
- https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/
- https://habr.com/company/dataart/blog/262817/
- https://habr.com/post/340146/
- https://habr.com/company/mailru/blog/115163/
- https://scotch.io/tutorials/authenticate-a-node-js-api-with-json-web-tokens
- https://egghead.io/courses/json-web-token-jwt-authentication-with-node-js
- https://www.digitalocean.com/community/tutorials/oauth-2-ru
- https://github.com/shieldfy/API-Security-Checklist/blob/master/README-ru.md
- https://www.youtube.com/watch?v=Ngh3KZcGNaU
- https://www.youtube.com/watch?v=R0-eoLp871s
- https://www.youtube.com/watch?v=u9hn3s2kUrg
- https://ain.ua/2020/02/29/adtech-bez-cookies/
- https://habr.com/ru/post/492830 (cookies SameSite)
And why JWT is bad
- http://cryto.net/~joepie91/blog/2016/06/13/stop-using-jwt-for-sessions/
- http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt-for-sessions-part-2-why-your-solution-doesnt-work/
- https://medium.com/@cjainn/anatomy-of-a-jwt-token-part-1-8f7616113c14
- https://medium.com/@cjainn/anatomy-of-a-jwt-token-part-2-c12888abc1a2
- https://scotch.io/bar-talk/why-jwts-suck-as-session-tokens
- https://t.me/why_jwt_is_bad
Комментарии периодически подчищаются
В этом уроке вы узнаете:
- Как получить OAuth-токен вручную
- Почему OAuth-токен может перестать действовать
- Что дальше
- Полезные ссылки
- Вопросы
В этом уроке мы подробнее расскажем об OAuth-токенах, их получении и использовании.
Из предыдущих уроков вы уже знаете, что API Директа использует OAuth-авторизацию. Напомним, что в каждом запросе к API необходимо указывать OAuth-токен. В токене зашифрована информация как о приложении, так и о пользователе. Токен используется для того, чтобы определить: от имени какого пользователя Директа приложение выполняет запрос; действительно ли пользователь разрешил этому приложению доступ к своим данным в Директе; есть ли у самого пользователя нужные полномочия для работы с теми рекламными материалами, к которым он обращается.
Таким образом, при работе с Директом через API нет необходимости передавать пароль от аккаунта пользователя. Достаточно передать OAuth-токен, что делает процесс работы с API Директа более безопасным. Но важно понимать, что для каждого пользователя в приложении требуется получить отдельный токен.
На начальных этапах разработки приложения достаточно вручную получить так называемый отладочный токен. В дальнейшем, при переходе к реальной работе, необходимо будет реализовать в приложении удобный для пользователей механизм получения токена, когда пользователь просто нажимает кнопку Разрешить в веб-интерфейсе Яндекс.OAuth, а затем Яндекс.OAuth передает приложению токен в автоматическом режиме.
Обратите внимание, что токен, полученный вручную, ничем не отличается от полученного в автоматическом режиме. Токен дает возможность управлять реальными рекламными материалами пользователя, независимо от способа, которым этот токен получен.
В одном из предыдущих уроков вы зарегистрировали приложение на Яндекс.OAuth, при этом в поле Callback URI #1 подставили URL для разработки. Если вы этого не сделали — оставили поле незаполненным или указали другое значение, перейдите на Яндекс.OAuth (https://oauth.yandex.ru) и отредактируйте настройки приложения: установите флажок Веб-сервисы, нажмите ссылку Подставить URL для разработки и сохраните изменения. Теперь вы можете вручную получить токен для тестового пользователя.
В роли тестового пользователя вы можете использовать тот же аккаунт разработчика, под которым вы зарегистрировали приложение и подали заявку на доступ. В данном курсе мы рассматриваем именно этот вариант.
Для получения токена вручную выполните следующие действия:
-
Войдите на Яндекс под своим логином.
-
Перейдите по ссылке
https://oauth.yandex.ru/authorize?response_type=token&client_id=ИДЕНТИФИКАТОР_ПРИЛОЖЕНИЯ
(вместо ИДЕНТИФИКАТОР_ПРИЛОЖЕНИЯ укажите идентификатор своего приложения).
-
На открывшейся странице нажмите кнопку Разрешить.
-
Яндекс.OAuth перенаправит вас на страницу, на которой отобразит токен. Токен будет также добавлен в адресную строку. Скопируйте токен, чтобы использовать его в запросах к API.
Внимание.
-
Никому не сообщайте токен — с его помощью можно получить доступ к данным пользователя в Директе.
-
Вы можете создать отдельный аккаунт тестового пользователя (или несколько аккаунтов). Для нового пользователя необходимо создать аккаунт в веб-интерфейсе Директа, выбрав страну и валюту расчетов, а также принять пользовательское соглашение в разделе API. Чтобы получить токен для пользователя, нужно войти на Яндекс под его логином и повторить описанную выше процедуру.
Совет. Если вам не удалось получить токен по какой-либо причине, воспользуйтесь подробной инструкцией.
Со временем токен может стать недействительным и потребуется получить новый.
Все токены пользователя будут отозваны, если:
-
пользователь изменил пароль на Яндексе;
-
пользователь нажал ссылку Выйти на всех компьютерах.
Токен, выданный для определенного приложения, будет отозван, если:
-
пользователь отменил доступ приложения к своим данным (эта возможность доступна в веб-интерфейсе Яндекс Паспорта);
-
разработчик приложения изменил права доступа для своего приложения;
-
срок жизни токена истек.
Полный перечень ситуаций, при которых Яндекс.OAuth отзывает токены, приведен в документации Яндекс.OAuth.
Итак, вы получили токен, с которым можете выполнять запросы к API. Впереди последний подготовительный этап: создание и настройка Песочницы — тестовой среды для отладки приложения. Затем мы перейдем непосредственно к составлению запросов к API.
Документация Яндекс.OAuth:
-
Чем отладочный токен отличается от полученного в автоматическом режиме?
Он дает доступ только к тестовой среде.Он выдается на одну неделю, после чего нужно получать новый токен.Отличается только способом получения, оба токена предоставляют одинаковые возможности.
Неверно.
Неверно.
Верно!
-
Может ли токен пользователя перестать действовать?
Нет, токен выдается навсегда.Да, может, например если пользователь сменил пароль от аккаунта или нажал кнопку Выйти на всех компьютерах.Нет, не может, пока пользователь сам не захочет поменять токен.
Неверно.
Верно!
Неверно.
-
Какие условия необходимы для получения отладочного токена?
Вы знаете идентификатор и пароль приложения.Подана заявка на тестовый доступ, и вы знаете идентификатор приложения.Войти на Яндекс под тем логином, для которого необходимо получить токен, и знать идентификатор приложения.Подана заявка на тестовый доступ, и вы авторизованы на Яндексе под тем логином, для которого необходимо получить токен.
Неверно.
Неверно.
Верно!
Неверно.
Using modern ways, there are better, more reliable ways to get access token field:
var urlString = 'http://localhost:3000/_oauth/google#access_token=ya29.5HxuYol1Io8JLeGePDznbfkkwu_PC4uodKwG8_1clFYAn9AgdOV1WGpOTNQP3s76HAsn7Y4zWw&token_type=Bearer&expires_in=3600';
var url = new URL(urlString);
// OR: If you want to use the current page's URL
var url = window.location;
var access_token = new URLSearchParams(url.search).get('access_token');
You can also see how this approach makes it easy to get the other parameters in addition. This URLSearchParams
approach is supported by all browsers except old instances of IE.
If the above doesn’t work (didn’t for me) just add ‘hash’ to window.location
, this is also single line code
var access_token = new URLSearchParams(window.location.hash).get('access_token');
Old Answer:
I like RegEx so here’s a RegEx answer:
var url = 'http://localhost:3000/_oauth/google#access_token=ya29.5HxuYol1Io8JLeGePDznbfkkwu_PC4uodKwG8_1clFYAn9AgdOV1WGpOTNQP3s76HAsn7Y4zWw&token_type=Bearer&expires_in=3600',
access_token = url.match(/#(?:access_token)=([Ss]*?)&/)[1];
access_token
is:
ya29.5HxuYol1Io8JLeGePDznbfkkwu_PC4uodKwG8_1clFYAn9AgdOV1WGpOTNQP3s76HAsn7Y4zWw
(Directly from the console)
Fiddle
To access your API, you must request an access token when authenticating a user.
To request an access token, make a POST call to the token URL.
Example POST to token URL
- cURL
- C#
- Go
- Java
- Node.JS
- Obj-C
- …
curl --request POST
--url 'https://{yourDomain}/oauth/token'
--header 'content-type: application/x-www-form-urlencoded'
--data grant_type=client_credentials
--data client_id=YOUR_CLIENT_ID
--data client_secret=YOUR_CLIENT_SECRET
--data audience=YOUR_API_IDENTIFIER
var client = new RestClient("https://{yourDomain}/oauth/token");
var request = new RestRequest(Method.POST);
request.AddHeader("content-type", "application/x-www-form-urlencoded");
request.AddParameter("application/x-www-form-urlencoded", "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&audience=YOUR_API_IDENTIFIER", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://{yourDomain}/oauth/token"
payload := strings.NewReader("grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&audience=YOUR_API_IDENTIFIER")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("content-type", "application/x-www-form-urlencoded")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)
fmt.Println(res)
fmt.Println(string(body))
}
HttpResponse<String> response = Unirest.post("https://{yourDomain}/oauth/token")
.header("content-type", "application/x-www-form-urlencoded")
.body("grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&audience=YOUR_API_IDENTIFIER")
.asString();
var axios = require("axios").default;
var options = {
method: 'POST',
url: 'https://{yourDomain}/oauth/token',
headers: {'content-type': 'application/x-www-form-urlencoded'},
data: new URLSearchParams({
grant_type: 'client_credentials',
client_id: 'YOUR_CLIENT_ID',
client_secret: 'YOUR_CLIENT_SECRET',
audience: 'YOUR_API_IDENTIFIER'
})
};
axios.request(options).then(function (response) {
console.log(response.data);
}).catch(function (error) {
console.error(error);
});
#import <Foundation/Foundation.h>
NSDictionary *headers = @{ @"content-type": @"application/x-www-form-urlencoded" };
NSMutableData *postData = [[NSMutableData alloc] initWithData:[@"grant_type=client_credentials" dataUsingEncoding:NSUTF8StringEncoding]];
[postData appendData:[@"&client_id=YOUR_CLIENT_ID" dataUsingEncoding:NSUTF8StringEncoding]];
[postData appendData:[@"&client_secret=YOUR_CLIENT_SECRET" dataUsingEncoding:NSUTF8StringEncoding]];
[postData appendData:[@"&audience=YOUR_API_IDENTIFIER" dataUsingEncoding:NSUTF8StringEncoding]];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://{yourDomain}/oauth/token"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
[request setHTTPMethod:@"POST"];
[request setAllHTTPHeaderFields:headers];
[request setHTTPBody:postData];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(@"%@", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
NSLog(@"%@", httpResponse);
}
}];
[dataTask resume];
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://{yourDomain}/oauth/token",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&audience=YOUR_API_IDENTIFIER",
CURLOPT_HTTPHEADER => [
"content-type: application/x-www-form-urlencoded"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
import http.client
conn = http.client.HTTPSConnection("")
payload = "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&audience=YOUR_API_IDENTIFIER"
headers = { 'content-type': "application/x-www-form-urlencoded" }
conn.request("POST", "/{yourDomain}/oauth/token", payload, headers)
res = conn.getresponse()
data = res.read()
print(data.decode("utf-8"))
require 'uri'
require 'net/http'
require 'openssl'
url = URI("https://{yourDomain}/oauth/token")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(url)
request["content-type"] = 'application/x-www-form-urlencoded'
request.body = "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&audience=YOUR_API_IDENTIFIER"
response = http.request(request)
puts response.read_body
import Foundation
let headers = ["content-type": "application/x-www-form-urlencoded"]
let postData = NSMutableData(data: "grant_type=client_credentials".data(using: String.Encoding.utf8)!)
postData.append("&client_id=YOUR_CLIENT_ID".data(using: String.Encoding.utf8)!)
postData.append("&client_secret=YOUR_CLIENT_SECRET".data(using: String.Encoding.utf8)!)
postData.append("&audience=YOUR_API_IDENTIFIER".data(using: String.Encoding.utf8)!)
let request = NSMutableURLRequest(url: NSURL(string: "https://{yourDomain}/oauth/token")! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data
let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
if (error != nil) {
print(error)
} else {
let httpResponse = response as? HTTPURLResponse
print(httpResponse)
}
})
dataTask.resume()
Parameters
Parameter Name | Description |
---|---|
grant_type |
Set this to “client_credentials”. |
client_id |
Your application’s Client ID. You can find this value on the application’s settings tab. |
client_secret |
Your application’s Client Secret. You can find this value on the application’s settings tab. To learn more about available application authentication methods, read Application Credentials. |
audience |
The audience for the token, which is your API. You can find this in the Identifier field on your API’s settings tab. |
Response
You receive an HTTP 200
response with a payload containing access_token
, token_type
, and expires_in
values:
{
"access_token":"eyJz93a...k4laUWw",
"token_type":"Bearer",
"expires_in":86400
}
Control access token audience
When a user authenticates, you request an access token and include the target audience and scope of access in your request. The application uses the /authorize
endpoint to request access. This access is both requested by the application and granted by the user during authentication
You can configure your tenant to always include a default audience.
Token Use | Format | Requested Audience | Requested Scope |
---|---|---|---|
/userinfo endpoint | Opaque | tenant name ({yourDomain} ), no value for audience parameter, no audience parameter passed |
openid |
Auth0 Management API | JWT | Management API v2 identifier (https://{tenant}.auth0.com/api/v2/ ) |
|
Your own custom API | JWT | The API Identifier for your custom API registered in the Auth0 Dashboard |
In only one specific instance, access tokens can have multiple target audiences. This requires that your custom API’s signing algorithm is set to RS256. To learn more, read Token Best Practices.
Multiple audiences
If you specify an audience of your custom API identifier and a scope of openid
, then the resulting access token’s aud
claim will be an array rather than a string, and the access token will be valid for both your custom API and for the /userinfo
endpoint. Your access tokens can have two or more audiences only if you use a single custom API as well as Auth0’s /userinfo
endpoint, y.
Custom domains and the Auth0 Management API
Auth0 issues tokens with an issuer (iss)
claim of whichever domain you used when requesting the token. Custom domain users can use either their custom domain or their Auth0 domain.
For example, suppose you have a custom domain, https://login.northwind.com
. If you request an access token from https://login.northwind.com/authorize
, your token’s iss
claim will be https://login.northwind.com/
. However, if you request an access token from https://northwind.auth0.com/authorize
, your token’s iss
claim will be https://northwind.auth0.com/
.
If you request an access token from your custom domain with the target audience of the Auth0 Management API, then you must call the Auth0 Management API from your custom domain. Otherwise your access token is considered invalid.
Renew access tokens
By default, an access token for a custom API is valid for 86400 seconds (24 hours). You can shorten the time period before the token expires.
After an access token has expired, you can renew your access token. To do so either re-authenticate the user using Auth0 or use a refresh token.
Learn more
- Validate Access Tokens
- Use Access Tokens
- JSON Web Tokens
- Refresh Tokens
- Identity Provider Access Tokens
- Management API Access Tokens