I am working on an LTI widget, that then needs to authenticate to the API to get additional information.
I'm struggling with trying to figure out how to process the API user authentication, and redirect back retaining the LTI information.
The request string that is returned looks like:
Array ( [x_a] => **********************
[x_b] => **********************
[x_c] => *********************************** )
The issue is that I have my PHP LTI script setup to only load if it meets the following condition:
if(!isset($_REQUEST['lis_outcome_service_url'])
|| !isset($_REQUEST['lis_result_sourcedid'])
|| !isset($_REQUEST['oauth_consumer_key'])
)
x_a is the user id, x_b is the user key .. what is x_c?
Any suggestions appreciated!
My answer is referring to the detailed topic on the IDKey Auth scheme for the Valence dev platform.
The part of the auth sequence you are referring to here is equivalent to the second stage of the sequence, just after the user has successfully authenticated themselves (when you chain on the back of an LTI launch like this, you know that the user driving the user-agent has already authenticated, because they wouldn't have otherwise been able to do the LTI launch) and the service sends back the long-lived user tokens to your service.
See steps 5 to 7 in the sequence notes, in the section called Using a third-party web application in the IDKey Authentication docs topic:
x_a={tokenID} – Unique ID associated with the long-lived token: the web application can provide this ID so that the service can precisely locate the web application/user context.
x_b={tokenKey} – Key associated with the long-lived token: the web application can use this as a key to generating session signatures.
x_c={tokenSig} – Token identity signature: the service joins (and delimits with an ampersand) the User ID (tokenID) and the User Key (tokenKey) to use as the base-string, and uses the Application Key as the key.
Note that you will need to use your Valence Application ID/Key pair in order to verify the token signature contained in x_c.
Remote plugins. Note that the Brightspace Remote Plugin service is a convenience service wrapper around LTI/external learning tools. The docs about Remote Plugins contain a fairly detailed walkthrough/sample that showcases a simple Python web-service Tool Provider implementation that receives a Brightspace LTI launch, and can turn around and use Valence API calls to get more information. You might find it useful to have a close look at that.
Related
I'm writing an application that uses keycloak as its user authentication service. I have normal users, who log in to keycloak from the frontend (web browsers), and service users, who log in from the backend (PHP on IIS). However, when I log in from the backend, keycloak uses HS256 as its signature algorithm for the access token, and thus rejects it for further communication because RS256 is set in the realm and client settings. To get around this issue, I would like to "pretend to be the frontend" to get RS256 signed access tokens for my service users.
For security reasons, I cannot give the HS256 key to the application server, as it's symmetrical and too many people can access the server's code.
I am currently debugging the issue using the same user/pw/client id/grant type both on the frontend and the backend, so that cannot be the issue.
So far I have tried these with no luck:
copying the user agent
copying every single HTTP header (Host, Accept, Content-Type, User-Agent, Accept-Encoding, Connection, even Content-Length is the same as the form data is the same)
double checking if the keycloak login is successful or not - it is, it's just that it uses the wrong signature algorithm
So how does keycloak determine which algorithm to sign tokens with? If it's different from version to version, where should I look in keycloak's code for the answer?
EDIT: clarification of the flow of login and reasons why backend handles it.
If a user logs in, this is what happens:
client --[login data]--> keycloak server
keycloak server --[access and refresh token with direct token granting]--> client
client --[access token]--> app server
(app server validates access token)
app server --[data]--> client
But in some occasions the fifth step's data is the list of users that exist in my realm. The problem with this is that keycloak requires one to have the view-users role to list users, which only exists in the master realm, so I cannot use the logged in user's token to retrieve it.
For this case, I created a special service user in the master realm that has the view-users role, and gets the data like this:
client --[asks for list of users]--> app server
app server --[login data of service user]--> keycloak server
keycloak server --[access token with direct granting]-->app server
app server --[access token]--> keycloak server's get user list API endpoint
(app server filters detailed user data to just a list of usernames)
app server --[list of users]--> client
This makes the the list of usernames effectively public, but all other data remains hidden from the clients - and for security/privacy reasons, I want to keep it this way, so I can't just put the service user's login data in a JS variable on the frontend.
In the latter list, step 4 is the one that fails, as step 3 returns a HS256 signed access token. In the former list, step 2 correctly returns an RS256 signed access token.
Thank you for the clarification. If I may, I will answer your question maybe differently than expected. While you focus on the token signature algorithm, I think there are either mistakes within your OAuth2 flows regarding their usage, or you are facing some misunderstanding.
The fact that both the backend and frontend use "Direct Access Granting" which refers to the OAuth2 flow Resources Owner Credentials Grant is either a false claim or is a mistake in your architecture.
As stated by Keycloak's own documentation (but also slightly differently in official OAuth.2 references):
Resource Owner Password Credentials Grant (Direct Access Grants) ... is used by REST clients that want to obtain a token on behalf of a
user. It is one HTTP POST request that contains the credentials of the
user as well as the id of the client and the client’s secret (if it is
a confidential client). The user’s credentials are sent within form
parameters. The HTTP response contains identity, access, and refresh
tokens.
As far as I can see the application(s) and use case(s) you've described do NOT need this flow.
My proposal
Instead what I'd have seen in your case for flow (1) is Authorization Code flow ...
assuming that "Client" refers to normal users in Browser (redirected to Keycloak auth. from your front app)
and assuming you do not actually need the id and access tokens back in your client, unless you have a valid reasonable reason. As the flows allowing that are considered legacy/deprecated and no more recommended. In this case, we would be speaking of Implicit Flow (and Password Grant flow is also discouraged now).
So I think that the presented exchange (first sequence with points 1 to 5 in your post) is invalid at some point.
For the second flow (backend -> list users), I'd propose two modifications:
Allow users to poll the front end application for the list of users and in turn the front-end will ask the backend to return it. The backend having a service account to a client with view-roles will be able to get the required data:
Client (logged) --> Request list.users to FRONTEND app --> Get list.users from BACKEND app
(<--> Keycloak Server)
<----------------------------------------- Return data.
Use Client Credentials Grant (flow) for Backend <> Keycloak exchanges for this use case. The app will have a service account to which you can assign specific scopes+roles. It will not work on-behalf of any user (even though you could retrieve the original requester another way!) but will do its work in a perfectly safe manner and kept simple. You can even define a specific Client for these exchanges that would be bearer-only.
After all if you go that way you don't have to worry about tokens signature or anything like that. This is handled automatically according to the scheme, flow and parties involved. I believe that by incorrectly making use of the flows you end up having to deal with tricky token issues. According to me that is the root cause and it will be more helpful than focusing on the signature problem. What do you think?
Did I miss something or am I completely wrong...?
You tell me.
I have an identity server built with Identity server 4. There is one main API with several angular web applications build by third party customers that access this API endpoint.
Now I would like to create a second API but its only for internal use with OUR official plugin. I am trying to figure out how to lock it down so that only our app can access it. I am not a fan security by obscurity and assuming that the third party's dont know its there so wont try and access it.
My first thought was to add a new scope for this API but by doing that its going to popup and ask the users for access to the data which isnt really need.
The only thing i can think of would be to check the client id some how in the API and add a policy for it. This really isnt right ether as to my understanding polciy should be checking stats of the user and not the client itself.
services.AddAuthorization(
options => {
options.AddPolicy("DevConsole", policy => IsClientId(xxxx)
}
);
Is it possible to lock down an API based upon a single client id? or am i going at this in the wrong way.
Another idea i had was to add another claim if they login with this client id which seams like overkill to me.
Example:
Lets say that I have an API endpoint that allows you to update the usersname. All users have access to their name this isnt a scope issue. However only our official app has access to update the usersname. Any app created by third party developers do not have access to the endpoint to update a usersname.
So our official plugin has a client id of 123 and yours has a client id of 321. A user logged though client id 321 can not access this endpoint. User logged in though client id 123 can.
I am starting to think this isnt possible because Oauth and Openid are completely user based. There is no way to validate the user based upon the client they authenticated with.
if I understand the problem correctly, I would create a new Client on Identity Server, for the "main API" and a new Resource for the "internal API"
This would allow the "main API" to also be a client, with client credentials grant type, therefore it has a id+secret and is allowed to request a token for itself. In this case, you will now request the newly created scope for in "internal API" and the users will have no knowledge that this entity evens exists.
After going back and forth with this with this it occurred to me that the client id is returned as a claim. So when i got in this morning i checked.
This should enable me to add a policy for only our official plugin.
services.AddAuthorization(options =>
{
options.AddPolicy("IsOfficalApp", policy => IsCheckOfficalClient());
});
This should enable me to lock down the API endpoints in question without requiring additional authorization from the users.
I've recently been experimenting with the Coinbase iOS SDK and I've been having issues retrieving a user's Ethereum, Litecoin and Bitcoin Cash balances and historic transactions. Currently, I've only managed to do this with Bitcoin, USD and EUR, which seems to be consistent with the behaviour of the demo app supplied by Coinbase.
I have configured an application on the Coinbase API Access page using OAuth2 and the generated client ID and secret are being used within the app.
The issue seems to stem from the fact that I modified the Coinbase iOS SDK to allow me to pass the account parameter as
‘all’. This, I had hoped, would allow me to view details of all user accounts (ETH, BTC, LTC etc.) however, I only get BTC, USD and EUR when calling ‘getAccountsList’ on the Coinbase object.
NSString *accessToken = [response objectForKey:#"access_token"];
Coinbase *client = [Coinbase coinbaseWithOAuthAccessToken:accessToken];
[client getAccountsList:^(NSArray *accounts, CoinbasePagingHelper *paging, NSError *error) {
for (CoinbaseAccount *account in accounts) {
// Only BTC, USD and EUR are in the accounts array at this point.
}
}];
This is surprising as the permissions request page correctly asks the user for all wallets, as you can see in the screenshot below:
I suspect a solution to this would be to use API keys, as you are able to specify exactly which accounts to grant access to. I plan to distribute the app however, so this technique should not be used.
Here is an example of the URL I am sending:
https://www.coinbase.com/oauth/authorize?response_type=code&client_id=CLIENT_ID_GOES_HERE&account=all&scope=balance%20transactions%20user&redirect_uri=com.example-name.example-app.coinbase-oauth%3A%2F%2Fcoinbase-oauth
Does anyone know how I can request access to all of a users accounts using OAuth and be able to retrieve details for each? Is the scope I defined incorrect in some way? The only alternative I can think of would be to request access one by one to each wallet and store individual access tokens. This wouldn't be a great user experience however.
Thanks!
Add the parameter
account=all
to the oAuth endpoint: https://coinbase.com/oauth/authorize?account=all&response_type=code...
Here are the details: https://developers.coinbase.com/docs/wallet/coinbase-connect/permissions
Coinbase Connect applications can request different access to user’s wallets. This access is defined by account parameter on OAuth2 authorization URL. Available options are:`
select - (default) Allow user to pick the wallet associated with the application
new - Application will create a new wallet (named after the application)
all - Application will get access to all of user’s wallets
I believe the iOS SDK is in need of an update. It still connects to old API version.
I'm using the original Coinbase SDK. No fork. in stead, next to the wallet:accounts:read scope, I also add ["accounts": "all"] as meta argument to the startAuthentication method.
AND. I am NOT using the getAccountList method, but instead the more general .doGet method with the api v2 accounts endpoint (so coinbase.doGet("https://api.coinbase.com/v2/accounts", parameters: nil) {(response, error) -> Void in
This gives me account info for all wallets. You do need to do some json processing on the response object in this case though.
First if you don't have one, you need to create an account on Coinbase
Then, please take a look first on the Coinbase digital api documentation, and I agree with you that it maybe easier to use the API to get data (if the target account is only your own personal account)
Because according to Coinbase:
API Key authentication should only be used to access your own account or merchant orders. If your application requires access to other Coinbase users’ accounts, do not use API Key. To securely access other Coinbase users’ accounts, use Coinbase Connect (OAuth2)
You have two possibilities:
USE API
Assuming user has grant wallet:accounts:read to the API key ( which allow you to List user’s accounts and their balances) according to the wallet permission documentation.
Once done, you may use the official wallet client libraries for iOS - coinbase is available through CocoaPods - by adding the following line to your Podfile: :
pod "coinbase-official"
USE OAuth2 PROTOCOL
According to this,
It is a slightly more complex integration than the API Key authentication method, but is more flexible. OAuth2 works well for web applications, as well as desktop and mobile apps.
You will find a lot of informations in the coinbase-connect integrating documentation, and you may also take a look on the official OAuth2 protocol website first.
Assuming you are OK with OAuth2, you will also have to ask user to grant you permission before requesting data.
As you need access to user wallet, you still have to request access token and add a scope parameter in the authorization request (Comma separated list of permissions (scopes) your application requests access to), if you need to see the full scopes list please refer yourself to this page.
The required scope is the same as API method: wallet:accounts:read, and your request will look like this:
GET https://www.coinbase.com/oauth/authorize?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=YOUR_REDIRECT_URL&state=SECURE_RANDOM&scope=wallet:accounts:read
After a successful request, a valid access token will be returned in the response (like this):
{
"access_token": "6915ab99857fec1e6f2f6c078583756d0c09d7207750baea28dfbc3d4b0f2cb80",
"token_type": "bearer",
"expires_in": 7200,
"refresh_token": "73a3431906de603504c1e8437709b0f47d07bed11981fe61b522278a81a9232b7",
"scope": "wallet:user:read wallet:accounts:read"
}
Once you get the access token, you can make any API call corresponding to the previous scope if you add the following header to the request:
Authorization: Bearer 6915ab99857fec1e6f2f6c078583756d0c09d7207750baea28dfbc3d4b0f2cb80
Finally, you may refer to the API reference documentation to see all possible API call and the relative scopes.
To conclude, you need to grant permission, then list the user accounts, then you may get any account resource:
Account resource represents all of a user’s accounts, including bitcoin, bitcoin cash, litecoin and ethereum wallets, fiat currency accounts, and vaults.
Regards
Still no luck.
Tried with adding param account=all. It gave me access to all wallets (exactly same as op). However, in code, I can only get BTC Wallet, BTC Vault, EUR Wallet and newly created BTC Wallet. The new wallet was created by adding param account=new.
Tried with adding param account_currency=BTC,ETH and chose ETH Wallet on oAuth authorization. Did getAccountsList which returned 0 objects and no errors from the server.
Tried with revoking all API application access in my Coinbase account (Settings->Security).
Scope: balance transactions user
Endpoint: .../oauth/authorize?account=all&response_type=code&client_id=%...
This is a bit of a theoretical question, however I'll try to be as detailed as possible. I've read a bunch of documentation on oath2/SSO implementation(I know they're not the same)- so I need to get beyond hand-wavy to actual system design. So here's what I think an Oauth2 implementation should look like.
The core design involves a bunch of micro services(which I'm calling app here) that all use the same authorization server.
To my understanding these are the end-points an auth server is supposed to provide.
Authorization Server
End point for an app to register -> Once registered the app is provided a client Id and client secret(these are essentially permanent
and don't change.
Endpoint for an user to register -> This request should come with the client Id and client secret so that the authorization server can
associate an user with an app.
Endpoint for an user to login -> If the user is an authorized user then he/she is provided an access token.
Endpoint with user details -> If an authorized app(correct client ID and secret) makes a request with an authorized user(correct access
token) then an user blob is returned.
Resource server(App)
Now that the resource server has this basic user data it can
deserialize the JSON object into its own user class and then have
one-to-one mapping to things like user_address/user_location etc.
This is my understanding of Oauth2-SSO. I'd highly appreciate some help around the rough edges. TIA !!!
I haven't implemented oath2 myself but the system I work on does use it, what you describe seems to be the same as what we use;
We initialize the client with an endpoint and the client secret and ID, then use our user's credentials to get a token (or an error message if the user/client credentials are invalid). From there we use the app's endpoints to call our applications. From what I can see our Oauth2 methods seem to do what you describe in your question, it should be correct.
The Eventbrite documentation on the ticket object indicates that it can contain a quantity_available or quantity_sold field, but that to see either of these fields "requires authentication". It doesn't give any more detail than that, though, and when I make calls to the event_search method using my app key, the tickets objects in the returned events do not contain quantity_available or quantity_sold keys.
What authentication is required to see these fields? Are they only visible to the owners of the event, or is it possible in some way for me to have the API return the number of tickets available for somebody else's event?
If this is not possible through the API, is the number of tickets remaining for an event publicly visible anywhere else on Eventbrite where I could get to it with a web scraper?
This needs to be called as an expansion. There are some more details here:
https://groups.google.com/forum/#!msg/eventbrite-api/sjMO-gV8-Go/uzw7GHq2_SEJ
Basically, calling it like so will populate the proper fields using your Apps OAuth token in python3:
import requests
eventbrite_response = requests.get(
"https://www.eventbriteapi.com/v3/events/<YOUR EVENT ID HERE>/?expand=ticket_classes",
headers = {
"Authorization": "Bearer <YOUR APP OAUTH TOKEN>",
},
verify = True, # Verify SSL certificate
)
print(eventbrite_response.json()['ticket_classes'][0]['quantity_sold'])
You can tailor the print function at the end to include more of the json data if you wish.
In order to read or write private data using the Eventbrite API, you will need to supply additional user-authentication tokens. This extra information lets Eventbrite know who should be authorized to access private data (including quantity_available and quantity_sold values) during the request.
Whenever you provide additional user access tokens, both public and private data will be available.
Authentication parameters include:
app_key: An application key (also referred to as an API key), identifies the application that is contacting the API. All API requests must include some form of application identification. If this is the only authentication token provided, the API request will be limited to publicly available data. Application keys have a default rate-limit of 1000 requests per day. You can get and manage your API keys here: https://www.eventbrite.com/api/key/
access_token: Recommended. OAuth2 access tokens are tied to a user account and an application key. Since the user-authorized application can also be identified via this token, it is the only authentication parameter that does not require an application key to be provided as well. Be careful not to expose these tokens to other users! Additional request headers are required when using access_tokens to contact our API: “Authorization: Bearer YOUR_ACCESS_TOKEN_HERE“. You can learn more about how to configure your application for OAuth2.0 here: http://developer.eventbrite.com/doc/authentication/oauth2/
user_key: Each Eventbrite account has an associated user_key. This token provides access to the related user’s account data, in addition to our publicly available data. This authentication method is preferred for use-cases that require private data-access where OAuth2.0 workflows are not possible. This token unlocks sensitive information, so be very careful not to expose this token to other users!
Here is an example of an API call that is using both the app_key and user_key parameters to return private data (remember to substitute in your own app_key and user_key):
https://www.eventbrite.com/json/user_list_events -G -d app_key=APPKEY -d user_key=USERKEY
You can also see the authentication documentation here: http://developer.eventbrite.com/doc/authentication/