Can I link multiple accounts with only one public token to exchange only one access token? - hyperlink

I am following the link flow which is things like:
create link token -> link from html page with the bank account that I chose -> get the public token from onSuccess event -> exchange access token.
However, I do want to use only one access token to manage all my accounts for API queries, is it possible to do so? If so, what's the step that I need to follow?
Thanks!
Tried the standard link flow but not working for multiple accounts bound.

No. A single public token can only be exchanged for a single access token, which gives access to a single Item.
Technically, one access token will control access to multiple accounts if the end user has multiple accounts at the same bank, but I don't think that's what you're asking about.

Related

Rleationship between Google Identity Services - Sign In with Google and User Authorization for Google APIs

I'm studying the Google document on "Google Identity Services" and seem to see two stories. One is called "Sign in With Google" which presents an attractive button where a user can sign-in with their Google account. The other is the Google Identity Services Authorization which grants an access token to make API calls.
What I am missing is whether or not there is a relationship between these two concepts/SDKs/functions. My mind is saying that I want a pretty button on my web page that I can use to sign in (ala Sign in With Google) AND I want the click of that button to give me an access token that I can use to invoke Google APIs. What I seem to be finding is that they are separate and discrete concepts with no obvious relationship between them. Is that correct?
References
Google Identity Services JavaScript SDK - Authorization
Sign in with Google
2022-06-26: Following a post from Blunt, I tried to add a hint but that didn't seem to make a difference. Here is the code I have been using. First, the index.html that loads the test:
<!DOCTYPE html>
<html>
<body>
<script src="https://accounts.google.com/gsi/client"></script>
<script src="./index.js"></script>
<div id="g_id_onload" data-client_id="XXX.apps.googleusercontent.com"
data-callback="handleToken" data-auto_prompt="false">
</div>
<div class="g_id_signin" data-type="standard" data-size="large" data-theme="outline" data-text="sign_in_with"
data-shape="rectangular" data-logo_alignment="left">
</div>
</body>
</html>
and the JavaScript loaded in index.js
const clientId = "XXX.apps.googleusercontent.com"
function handleToken(x) {
debugger;
const client = google.accounts.oauth2.initTokenClient({
client_id: clientId,
hint: "myemailaddress",
scope: 'https://www.googleapis.com/auth/calendar.readonly',
callback: (response) => {
debugger;
},
});
client.requestAccessToken();
}
What I am finding is that I get a the button in the web page as desired ... I click the button, I am prompted to sign in to Google and then the debugger statement (the first one) in the handleToken function is reached. The code progresses and then I am prompted to sign in to Google a second time. It had been my hope that the first sign-in would have been sufficient and somehow context would be preserved for the authorization.
In the new Google Identity Service, the authentication (sign-in) and authorization (access to api's) are separated, but not entirely distinct.
I have an article that explains this, and a reference implementation for pure client-side solution. npm install gothic will get you that reference implementation.
But here are the details:
(1) The sign-in with Google gives you the pretty button. Signing in provides user information encoded in a JWT. But none of this provides an access token.
(2) To obtain the authorization, you need to drive a second, sequential process. To expedite this process you can use the email address from the sign in process as an optional hint parameter to the authorization library, but the first time the user accesses it, they will still need to go through an explicit authorization process, depending on what api's (scopes) you need to access.
With regard to authorization, there are two models:
(1) Token-based. This is the pure client-side version. With this, you ultimately provide your clientId, your API-key, the discovery uri and the scopes to the library, and you get back a 1-hour token, that authorizes use of the APIs your app needs. As I mentioned, this requires an explicit prompt to the user the first time, and is click-free thereafter. But you will need to renew that token every hour, or on each page refresh.
(2) Code-based. This requires you to have a server-side to your app as well. In this model, your client obtains a code from Google, and hands that to your server. Your server exchanges it for an access token and a refresh token, and thereafter uses the refresh token to obtain new access tokens.
The server-side, code-based model is the more secure, and can ultimately provide the better UX, but it is of course more architecturally complex.
If you have specific code you are trying to get working, feel free to share and we can help.
To start with you need to understand the difference between two concepts.
Authentication and authorization.
authorization
Authorization is the act by which a user who owns private data grants an application created by a developer to access their data. Authorization is requested by showing a consent screen. A user consents to the application accessing their data, the amount of access a user grants is designated by the scopes requested.
In the image below the application Google Oauth 2.0 Playground is asking me for permission to See and download all my google drive files.
I requested the "https://www.googleapis.com/auth/drive.readonly" scope when requesting authorization.
Authorization is Oauth2. it returns an access token and a refresh token. Access tokens can be used to access api endpoints. In this case the google drive api. Access tokens are short lived and expire after an hour. The refresh token can be used to request a new access token at any time when the user is off line. This is why there is no way for an api to see if the entity preforming the call is actually the user who owns the data, it may infact be a third party application using an access token and refresh token to gain access to the users data.
You can grant an application access to your data and they can continue to request your data until you revoke that access.
Authentication
Authentication on the other hand is sign in. It is prof that the what made the call is in fact the user who owns the account. They must have typed their user name and password or logged into their account. Or already be logged into their google account on their machine. If you have two google accounts signed in like I do they you will be promoted for which user you would like to use.
So authencation authenticates or proves, that the user making the call is in fact the owner of the account the data resides on. Authentication is something called Open Id connect and was built on top of Oauth2.
The scope that are email, profile, and openid either profile or openid is required email is optional. Open id connect basically gives you access to a users profile information. If you are using a library you wont normally see this scope its normally added internally. If the only scope that is requested is a open id connect scope then the user will not see a consent screen. In the call above I added profile scope so you can see it is also asking for access to profile data but its grayed out the user cant not accept it.
Open id connect returns something called an id token. the id token is very short lived its around five minutes. An id token is a jwt so you can use jwt.io to decrypt it. Within the jwt you can find a number of claims. This claims give your application information about who the user is that just signed into your system.
Of note, name, picture, locale (language), and sub, sub is the users internal user id on the calling authentication server. So you can use the google sub id to link this users google account to your internal user storage. Then when ever this user logs in using google you will know which user it is in your system by matching the id.
{
"iss": "https://accounts.google.com",
"azp": "40740878192.apps.googleusercontent.com",
"aud": "407408718192.apps.googleusercontent.com",
"sub": "1172004532672775346",
"at_hash": "Aa0FT7DLf38T_onVI_ca8g",
"name": "Linda Lawton",
"picture": "https://lh3.googleusercontent.com/a-/AOh14GhroCYJp2P9xeYeYk1npchBPK-zbtTxzNQo0WAHI20=s96-c",
"given_name": "Linda",
"family_name": "Lawton",
"locale": "en",
"iat": 1656311886,
"exp": 1656315486
}
Note.
Sign-in will not grant you an access token unless you are able to add additional scopes to it, like drive, or calendar. I have yet been able to figure out how to add additional scopes to googles new JavaScript web login library.
The thing is what exactly are you trying to do. Do you want to log a user into your system. Or do you just want access to some private user data of theirs through one of googles apis?
In order to prevent the authorization flow to re-request for authentication, you need to add the prompt and the hint properties to the initTokenClient or the initCodeClient method config object (depending on which one of them you use - see here).
Here is how it looks like:
google.accounts.oauth2.initTokenClient({
client_id: 'YOUR_GOOGLE_CLIENT_ID',
callback: 'YOUR_CALLBACK',
hint: 'THE_USER_EMAIL',
prompt:''
});
As mentioned, the same is true for initCodeClient.
In the same way, you can pass those properties not only on initialization phase, but on the event phase as well, with the requestAccessToken or requestCode, respectively. Here it is:
googleClient.requestAccessToken({
prompt: '',
hint: 'THE_USER_EMAIL'
});
In this code, googleClient is a JS const that stores the Google codeClient / tokenClient object.
Explanation:
The prompt parameter with empty string tells Google to not request authentication if the user is already authenticated. This will let the flow to continue right to the authorization phase.
This is not enough, because if there is more then one account connected to the browser, Google can not decide to WHICH one of them he should ask for authorization API. This situation will cause the authentication popup to show again, in order to let the user to choose an account.
This is where the hint parameter comes to play, it lets Google to know what accont to use, then, if this account is already connected, Google is able to pass the entire authentication popup and go right away to the authorization one.
In order to get the user email, you should use the credential property, returned from the authentication API of google.accounts.id.initialize. This credential is a JWT string, after decoding it with the JS atob method, you'll be able to extract the user email from it, beside other properties. For more details regarding to this, please check here.

What oauth pattern to follow for a super user assuming the identity of a customer

I'm working at a company where we have a standard JWT token given to an end user. This user will get their JWT access token by going through the authorisation code oauth flow. By passing their access token into the Authorization header they can make calls into the microservice api's.
We now have a scenario where we need someone from the customer service centre assume the identity of an end user for the purpose of giving the service centre representative access to the users data for short period of time.
To solve this we have discussed having two access tokens flowing into the Authorization header in the microservice api's. The first would represent the customer service centre representative and the second would be the users access token but i am confused on how to best architect this solution.
Can anyone recommend a good solution staying as close to open id connect standards as possible. Microsoft seem to have an oauth flow named on behalf of which kind of matches what i want but seems more like it caters for a system on behalf of a user where I want a user on behalf of another user.
thanks
LONGER TERM
User Managed Access may provide solutions in this area:
End User sets a policy at the Authorization Server for their personal resources
A Company Administrator applies a policy at the Authorization Server for corporate resources (for multiple users)
A Requesting Party (app) presents claims as proof that they meet the policy
REAL WORLD
Almost no Authorization Servers support this capability, and even those that do may not do what you want. It is more than an OAuth pattern though, since a solution also ties into back end behaviour.
WHAT I WOULD DO
Build a solution around claims:
Service centre user logs in, to establish their own identity
After login, lookup claims, to see if the user has 'super' rights
If so, your UI presents an option to act on behalf of another user
Service center user types in email of who they are acting as
Update claims with the second identity
Authorization needs to take both identities into account
Auditing needs to log both identities
The above list hints at requirements, and of course not all of these can be solved with OAuth, but claims should give you the flexibility you need.
See my claims write up for how you could apply this pattern to collect claims from multiple places - not just access tokens. In your case, the ApiClaims object could include your database user ids for both users.

OAuthPrompt/SigniIn for AzureAD always defaults to SSO credentials. How to request for alternate creds?

I have made a bot for a customer.
the purpose is to run admin commands through a secured API.
For this, they need to be
Logged on the teams using their standard account
When they execute an admin command, bot asks for OAuth Login (Connection is set to AzureAD v2 mode).
In teams / tester in portal, it never asks for credentials, it just defaults to the logged on user.
How do I make it always just ask for credentials?
One way is to make a seperate AzureAD, but that then requires customer to pay for Premium AD once again, to be able to assign the AzureAD Roles defined for the admin API to groups and not single users.
So this is not a very good solution.
They can also add teams license to their admin account, but that breaks the whole workflow and reason to have a bot. cause they would have to have a browser open with admin creds logged to teams.
I hope this is possible, otherwise I am super sad, that some amazing admin scenario possibilities are lost. Unfortunately none of our enterprise customers, would allow to trigger various admin APIs using the employees standard account.
I'm not sure if this totally answers your question and I'm a bit confused by what you want. but from what I'm understanding,
I followed this documentation here:https://learn.microsoft.com/en-us/microsoftteams/platform/bots/how-to/authentication/add-authentication?tabs=dotnet%2Cdotnet-sample
the sample has a bot that authenticates with azure ad, it pops up the azure log in window every time for me in teams. a please sign in button appears, then you click sign in, and it pops up the login window which then you can get the token for and use that to call graph and etc.
I tested this out and when I talk to the bot, it always asks me to sign in, so hopefully this is what you're looking for? if not, please specify which part its missing, thanks
edit: the instructions are for the aad v1 endpoint, but if you want to use the v2 endpoint, it's nearly the same. just less to type, also you need to enter the scopes that you give api permissions to, eg "User.Read User.ReadBasic.All etc etc"
Update
So upon further discussion I saw what your issue was. what you need to do is the following. in the bot channels registration -> settings -> oauthconnectionsettings, take note of your values and delete it.
Then create a new one, under same name,
with these parameters,
service provider: Oauth 2 Generic Provider
ClientID: same as before
secret: same as before.
scope list delimiter: ' '
authorization URL Template: https://login.microsoftonline.com/common/oauth2/v2.0/authorize (Replace Common with your tenant, just because i was using common)
Auth URL Query string template (this is key): ?client_id={ClientId}&response_type=code&redirect_uri={RedirectUrl}&scope={Scopes}&state={State}&prompt=login
token url template: https://login.microsoftonline.com/common/oauth2/v2.0/token (again replace common with your tenant id)
token url query string tempalte : ?
token body template: code={Code}&grant_type=authorization_code&redirect_uri={RedirectUrl}&client_id={ClientId}&client_secret={ClientSecret}
refresh url template: https://login.microsoftonline.com/common/oauth2/v2.0/token (again replace common with your tenant id)
refresh url query string: ?
refresh body template: refresh_token={RefreshToken}&redirect_uri={RedirectUrl}&grant_type=refresh_token&client_id={ClientId}&client_secret={ClientSecret}
scopes: Mail.Read Mail.Send User.Read User.ReadBasic.All (or whatever your scopes are)

Google OAuth2 API Separate Tokens by Subdomain

I have a multi-tenanted app that I need to integrate with a Google API endpoint, lets say the Calendar API.
The application is organized much like Slack. You can create a namespace and invite users to it. The subdomain is used to separate namespaces, so there could be: foo.domain.com, bar.domain.com, and baz.domain.com.
A user, can belong to multiple namespaces, much like in slack where you can belong to different teams. So John can be a member of both foo and bar.
The problem is, when John decides he wants to give foo access to his calendar info, Google links the authorization to domain.com rather than foo.domain.com. When I attempt to give access his calendar to bar as well, there is no refresh token because technically John has already authorized the access... but I would like these to be treated independent. So that John is able to revoke access to foo.domain.com but continue to have bar.domain.com access his calendar data.
Is there a way to create independent authorizations for the same user to the same app? I can't share the refresh_token across subdomains as they may be physically separated, and I can't create a different app for each subdomain as they are dynamically generated.
The way authentication works is that its based upon the client you created in Google developer console.
If John grants your client access to his calendar data then that client will have access to his calendar data. Google has no way of knowing that its your foo or bar subdomains that have been granted access.
Multiple client option
You should probably created different client credentials for each of the different sub domains. Thats probably going to be the most logical way of doing it.
Single client option
Besides doing that you could store the information in your database someplace John has granted access to foo but not bar and store the refresh token for foo but not for bar and if he wants to delete it for foo then he can do that. You wont have to worry about keeping the refresh tokens updated as a user can technically have up to 50 refresh tokens associated with a single client.
Just watch it with revoke if the user does a revoke its going to revoke access to everything not just a single app.
Google's OAuth implementation only returns a refresh token in the response if the user explicitly clicked the "Authorize" button. This always happens the first time the user is prompted for authorization, but by default the consent screen is skipped when the same application asks for authorization again for the same scopes.
You can override this behavior, and force the user to see the consent screen again by adding the parameter prompt=consent in your authorization URL:
https://developers.google.com/identity/protocols/OpenIDConnect#re-consent
Doing so will ensure that a refresh token is returned each time. Keep in mind that a given user-application pair can only have 50 refresh tokens active at a time, after which older tokens will be invalidated:
https://developers.google.com/identity/protocols/OAuth2#expiration

Enabling OAuth support in Square Connect

I have an application that currently integrates into my merchant account using my access token. Early discussion with neighborhood merchants indicates some positive interest. I want to integrate OAuth support so that I can try to get traction with those merchants.
Though https://docs.connect.squareup.com/api/connect/v1/#navsection-oauth has information, I seek some additional clarification.
(i) Access using https redirect-url is denied at Square Connect Authorize has an answer "By default the OAuth flow is disabled for applications which is why you are seeing the "Authorization not allowed" failure. If you wish to enable OAuth flow for your application then you need to contact Square." #SquareConnectSupport: I have sent an email to Developer#Square, please let me know what else do I do.
(ii) Here is how I think it will work - the OAuth integration (Please confirm)
User types in browser say "mysnow.com/square"
The Handler at "mysnow.com/square" allows user to type in an ID this ID is local to mysnow
Then the Handler at "mysnow.com/square" directs the merchant to https://connect.squareup.com/oauth2/authorize along with my application id, permissions and redirect url.
The handler then receives a notification code with AuthZ Code at the redirect URL previously provided.
Next the handler obtains the Access token (using the AuthZ code)
Finally, the handler then saves the ID, the AuthZ code , the relevant Access Token and the date/time stamp (when the token was obtained) as a tuple in a safe data store.
(iii) Using the Access Token
When there is need to access merchant data of given ID, then use the ID to get the Access Token. Use this Access Token to manage the permitted data (based on permission)
Renew the access token periodically.
​(iv) For testing purposes, I create few test/dummy merchants?​ Or do you have dummy merchant accounts that I can use for testing.
You can authorize up to ten merchants through the OAuth flow without approval from Square, which should be enough to get your integration running and tested. If you would like to make it more broadly available, you will need to contact Square about getting the app in the Square App Marketplace.
That looks essentially correct. The best practice for OAuth is something like this:
Merchant visits your landing page (e.g. mysnow.com/square) and clicks an action to start using your square integration.
Merchant's browser is redirected to the OAuth page (https://squareup.com/oauth2/authorize?client_id=YOUR_CLIENT_ID&scope=LIST_OF_OAUTH_SCOPES_YOU_NEED)
Merchant authorizes your application to access their data and is redirected back to your site. In the URL is an authorization code
Your backend makes an API call to Square to exchange the authorization code for an access token. It then uses that access token to look up information about the merchant and pre-populate fields of your signup form (e.g. you can get name, email, etc)
With a partially populated signup form on your site, merchant is prompted to complete their registration with your service.
There isn't really a way to create "dummy" merchants, but you can sign up for multiple merchant accounts with the same identity information, as long as you use a different email for each one. If you have GMail, you can do "you+someword#gmail.com" and the mail will be redirected to "you#gmail.com", so you don't need to create a bunch of email accounts to have unique email addresses.

Resources