I have an authentication server where an user can login (user/password) and it sends back a token so the user can access a private api.
I want to implement social login (e.g. google oauth2) but the redirect flow of these logins prevent me to send back a token.
How can I achieve that ?
If understand you correct you want pass your custom data (token) to OAuth2 login process. If so you have state field in url for it. This field prevented during redirects and sent back to you result page.
Pice of sample code in python
state = any_data_base64_coded_or_references
flow = flow_from_clientsecrets(....)
next_page = str( flow.step1_get_authorize_url() + '&state=' + state );
But be carefull url can ba cutted in 255 bytes. So better pass references to your internal entry
Related
I would like a user to login with tikok on the web and get his basic information like:
avarat_url
union_id (uniq user identifier provided by tiktok)
display_name
The Tiktok Login Kit for Web Documentation seems to be missing a full example on how to implement the full sequence of calls. Also some things are not explained at all (like the callback URL). Can someone share their full solution with code example on how to integrate tiktok login onto a webpage.
Heres a full example of the tiktok login for web implementation:
setup a tiktok developer account https://developers.tiktok.com/
create a new app, this will generate a CLIENT_KEY and CLIENT_SECRET.
create 2 backend endpoints that you control, for example:
https://example.com/auth : builds a tiktok URL and redirects the user to that endpoint (where the user will be prompted to login).
https://example.com/authCallback : once the user has finished the login with tiktok flow, tiktok sends an authorizationResponse to this endpoint. The authorizationResponse contains info that you need to fetch the users data.
in section "Platform Info": insert the callback URL and redirect domain. The callback URL being the second of the 2 server endpoints listed above. Tiktok will send the authorizationResponse to that URL once the user successfully loggs in and grants or declines the required permissions. In redirect domain simply add the domain without the exact path.
fill out all info for your app and wait for approval, this can take up to 1-3 days.
once approved, you are ready to implement the full flow, which consists of multiple steps/requests.
(A) send the user from your frontend to your first backend endpoint https://example.com/auth. From there, the user will be redirected to the tiktok auth page.
(B) once the user finished the authorization, tiktok sends a authorizationResponse to your callback URL (https://example.com/authCallback), which contains a variable code. With the code you can request the access_token and open_id of the user.
(C) use the access_token and open_id to request basic user info.
(A) Send User to Tiktok Authentication Page
In your frontend, redirect the user to https://example.com/auth. Then run the following nodejs backend code on your /auth route. For this example we use an express app (req = request object, res = response object):
// IMPORTANT, it is your responsibility to store a csrf token
// in your database, to be able to prevent xss attacks, read more
// here (section 2.1) => https://developers.tiktok.com/doc/login-kit-web
const createCsrfState = () => Math.random().toString(36).substring(7);
const csrfState = createCsrfState();
res.cookie('csrfState', csrfState, { maxAge: 60000 });
let url = 'https://open-api.tiktok.com/platform/oauth/connect/';
url += `?client_key=${CLIENT_KEY}`;
url += '&scope=user.info.basic';
url += '&response_type=code';
url += `&redirect_uri=${encodeURIComponent('https://example.com/authCallback')}`;
url += '&state=' + csrfState;
// redirect the user to the generated URL
// user will be prompted to login with tiktok
// and authorize needed permissions
res.redirect(url);
This code redirects the user to a tiktok url, where the user is prompted to sign in with tiktok and grant access.
(B) Handle authorizationResponse, use code to get access_token and open_id
Once the user finished the login process, tiktok sends an authorizationResponse to your second backend server endpoint https://example.com/authCallback. In that callback you recieve variables state and code.
// express example with
// `req` = request object
// `res` = response object
// check if the csrf token is valid
// its the developers responsibility
// to setup a validation logic.
if (!validateCsrfToken(req.query.state)) {
throw new Error("invalid csrf token");
}
async function getAccessTokenAndOpenId(code, TIKTOK_CLIENT_KEY, TIKTOK_CLIENT_SECRET) {
let urlAccessToken = 'https://open-api.tiktok.com/oauth/access_token/';
urlAccessToken += '?client_key=' + TIKTOK_CLIENT_KEY;
urlAccessToken += '&client_secret=' + TIKTOK_CLIENT_SECRET;
urlAccessToken += '&code=' + code;
urlAccessToken += '&grant_type=authorization_code';
const resp = await axios.post(urlAccessToken);
return {
accessToken: resp.data.data.access_token,
openId: resp.data.data.open_id,
};
}
const code = req.query.code;
const { openId, accessToken } = await getAccessTokenAndOpenId(code, TIKTOK_CLIENT_KEY, TIKTOK_CLIENT_SECRET);
(C) Get basic user info
async function getBasicInfo(accessToken, openId) {
let urlBasicInfo = `https://open-api.tiktok.com/user/info/`;
const data = {
access_token: accessToken,
open_id: openId,
fields: [
"open_id",
"union_id",
"avatar_url",
"avatar_url_100",
"avatar_url_200",
"avatar_large_url",
"display_name",
],
};
const resp = await axios.post(urlBasicInfo, data);
return resp.data.data.user;
}
const userBasicInfo = await getBasicInfo(accessToken, openId);
// 🥳 done!
I have a requirement to integrate with an external authentication provider which they require us to generate the state & nonce and using these parameters as an input for the embedded JS to generate the QR code, this QR code will be scanned by mobile for authentication.
for the standard login with external authentication provider, we call the Challenge() method to redirect to the login page, and the redirect url contains the state & nonce itself, is there a way to generate/get them without redirection?
If I generate random nonce & state at frontend side then scanning the QR code and completed the authentication in mobile, it returned the authentication code and threw "unable to unprotect the message.State." exception at the IS4, I tried to disable the state validation but it does not work.
configureOptions.ProtocolValidator = new OpenIdConnectProtocolValidator()
{
RequireState = false,
RequireStateValidation = false,
};
Any help would be much appreciated.
We use IdentityServer3 (IdSvr3) for authorization/authentication. We want to offer the ability for our end user (or resource owner: RO) to log in (log through) to a second trusted website (site B) without login in to site B also, after they have already logged in to an initial website (site A). Site B administers a different set of resources for the RO. It is important that the RO is not redirected to the IdSvr3 login/consent screen. A possible approach I found so far is: inside site A an access token is created by calling RequestResourceOwnerPasswordAsync (passing username and password plus scope = "openid ..."). This access token is send to site B with which the RO can be authenticated. Site B retrieves the user info by calling the connect/userinfo endpoint. I want to know if this is a correct approach/flow. We assume that the RO will always enter site A first, not site B.
Thanks in advance for taking your time to think with me about this.
what you can do here is to send a authorize request to identity server for Site B Scope and request id_token or reference token. Make sure while sending the authorize request to idsrv you are using prompt=none, this way you will get the access_token without showing a consent to the user again if the user is already logged-in to site A.
Below example is doing the same from a JS file. In Site A you can refer to this script file and execute the script using IIFE.
function getIdentityServerURL() {
var url = global.appSettings.identityServerURL
+ "/connect/authorize?client_id=siteB&response_type=id_token token&redirect_uri="
+ global.appSettings.siteBUrl + "/Main/SsoCallback&scope=siteBscope openid email roles&prompt=none&nonce="
+ genNonce();
return encodeURI(url);
}
The code above will redirect you to SsoCallback page where you can create a virtual iframe and post the token back to site B after reducing the result from authorize request. Refer to code below.
<script type="text/javascript">
var identityresult = window.location.hash.split('&').reduce(function (result, item) {
var parts = item.split('=');
result[parts[0]] = parts[1];
return result;
}, {});
window.parent.postMessage(identityresult, '*');
your script can listen to postmessage event. Hope this helps.
Does anyone have sample code or clear instructions on how to use libEtPan to connect to a GMail account using OAuth? I couldn't find anything.
Details for OAuth in GMail are here: http://code.google.com/apis/gmail/oauth/
libetpan has some documentation in its header files, for IMAP it's in https://github.com/dinhviethoa/libetpan/blob/master/src/low-level/imap/mailimap_oauth2.h
/*
mailimap_oauth2_authenticate()
Authenticates the client using using an oauth2 token.
To gather a deeper understanding of the OAuth2 aunthentication
process refer to: https://developers.google.com/gmail/xoauth2_protocol
For a quick start you may follow this brief set of steps:
1. Set up a profile for your app in the Google
API Console: https://code.google.com/apis/console
2. With your recently obtained client_id and secret
load the following URL (everything goes ina single line):
https://accounts.google.com/o/oauth2/auth?client_id=[YOUR_CLIENT_ID]&
redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&
response_type=code&scope=https%3A%2F%2Fmail.google.com%2F%20email&
&access_type=offline
3. The user most follow instructions to authorize application access
to Gmail.
4. After the user hits the "Accept" button it will be redirected to another
page where the access token will be issued.
5. Now from the app we need and authorization token, to get one we issue a POST request
the following URL: https://accounts.google.com/o/oauth2/token using these parameters:
client_id: This is the client id we got from step 1
client_secret: Client secret as we got it from step 1
code: This is the code we received in step 4
redirect_uri: This is a redirect URI where the access token will be sent, for non
web applications this is usually urn:ietf:wg:oauth:2.0:oob (as we got from step 1)
grant_type: Always use the authorization_code parameter to retrieve an access and refresh tokens
6. After step 5 completes we receive a JSON object similar to:
{
"access_token":"1/fFAGRNJru1FTz70BzhT3Zg",
"refresh_token":"1/fFAGRNJrufoiWEGIWEFJFJF",
"expires_in":3920,
"token_type":"Bearer"
}
The above output gives us the access_token, now we need to also retrieve the user's e-mail,
to do that we need to perform an HTTP GET request to Google's UserInfo API using this URL:
https://www.googleapis.com/oauth2/v1/userinfo?access_token=[YOUR_ACCESS_TOKEN]
this will return the following JSON output:
{
"id": "00000000000002222220000000",
"email": "email#example.com",
"verified_email": true
}
#param session IMAP session
#param auth_user Authentication user (tipically an e-mail address, depends on server)
#param access_token OAuth2 access token
#return the return code is one of MAILIMAP_ERROR_XXX or
MAILIMAP_NO_ERROR codes
*/
LIBETPAN_EXPORT
int mailimap_oauth2_authenticate(mailimap * session, const char * auth_user,
const char * access_token);
LIBETPAN_EXPORT
int mailimap_has_xoauth2(mailimap * session);
I haven't tried it out myself yet, but when I get around to implement it I'll post a link of the implementation.
Update March 2021
I finally got around to implement support for Google OAuth 2.0 in my email client nmail now. The commit can be viewed here but essentially I ended up doing steps 2-6 above in a separate external script, as libetpan does not do the token generation/refresh for us. The token handling is fairly straight-forward - see oauth2nmail.py for example.
I'm working with client who provided me with somewhat vague
instructions. Here's what I'm doing (using CommonsHttpOAuthConsumer as
consumer and DefaultOAuthProvider as provider)
I'm able to get response token from doing this:
String requestToken = provider.retrieveRequestToken
(OAuth.OUT_OF_BAND);
this is in form of URL with params so I'm parsing the actual token
out for example:
https://foobar.com/oauth/login_authorize?oauth_token=XRFCGPbES3M2bYZy...
Now - the instructions that I get say:
Given the request token obtained in step 1, login with the user’s
credentials (name and password) as POST parameters and sign the
request with the request token/secret
POST https://foobar.com/oauth/login_authorize
That's where I'm having difficulties. Obviously I have to input that
requestToken somewhere so I do this (post is HttpPost that contains user credentials):
consumer.setTokenWithSecret(requestToken, SECRET);
consumer.sign(post);
It doesn't work. It actually generates 200 status but what I get is a
generic error message.
retrieveRequestToken does not return a request token, it returns an authenticationUrl that you need to send your users to so they can sign in. Request token is saved in provider object.
String authenticationUrl = provider.retrieveRequestToken( call_back_url )
Note: According to the oauth standard the users sign in on the providers site with their credentials. After they have done that you (as a consumer) can get the Access Token and after that you can access their data on the providers site.
// After user has signed in
provider.retrieveAccessToken(null)
// access token is saved in provider and provider knows which consumer uses it
// so now you can sign with your consumer and connect with the request
URL url = new URL( protected_resources_url )
HttpURLConnection request = (HttpURLConnection) url.openConnection();
consumer.sign(request)
request.connect()
If you have the user credentials you can do the authorization in your script
// Using grails and functional-tests
get(authenticationUrl)
// Image the site shows a simple form with username/password and a login button
setRedirectEnabled false
form {
username = "mario"
password = "peach"
click "login"
}
And then do retrieveRequestToken and the code mentioned above
Hope this helps you
// Jonas