I have a SwaggerHub definition and I want to use the 'Try it out' function to pull data from my API Gateway page.
This API is restricted using a Cognito Authorizer.
Currently I have created a separate web page where I log into my Cognito UserPool and then it returns the id_token. I then copy this value and paste it into my SwaggerHub definition in the Authorization header value each time I make a call.
Is there a way I can do the authorisation directly from SwaggerHub rather than having to get the id token from another method first?
Yes you can, using security schemes. See https://swagger.io/docs/specification/authentication/.
See https://app.swaggerhub.com/apis/kanjih-ciandt/dsco-platform_api/3.0 for oauth2 example. It's not my API but one I found searching on SwaggerHub.
I've managed to set it up in our project and it's working fine even with MFA.
Just follow this steps:
In swagger definition (openApi 3.0):
components:
securitySchemes:
cognito:
type: oauth2
description: Using Cognito oAuth
flows:
authorizationCode:
authorizationUrl: 'https://YOUR_DOMAIN.auth.YOUR_REGION.amazoncognito.com/oauth2/authorize'
tokenUrl: 'https://YOUR_DOMAIN.auth.YOUR_REGION.amazoncognito.com/oauth2/token'
refreshUrl: 'https://YOUR_DOMAIN.auth.YOUR_REGION.amazoncognito.com/oauth2/token'
scopes:
phone: 'Phone access'
email: 'Email access'
YOUR_SCOPES: 'CUSTOM SCOPES'
For it to work, you have to add the swaggerHub callback url in the configuration of the Cognito client you are using, which is: https://app.swaggerhub.com/oauth2_redirect
Then you can get the token directly from SwaggerHub, using the client_id and client_secret of your client, and you will be redirected to the login page, and then redirected back to swagger with the auth token.
Related
Here is my aim: I would like to get an access token to call web api from my Spa application.
I created 2 azure b2c applications; one for web api and other for spa application(client).
I added scopes(api.read) by exposing api in web api application. I granted permission to these scopes from spa application.
I created one userflow with Sign up and sign in policy.
To generate the token, I used PKCE flow by getting auth code.
POST
https://tenant.b2clogin.com/tenant.onmicrosoft.com/policy/oauth2/v2.0/token
grant_type: authorization_code
client_id: api_appid
scope: https://tenant.onmicrosoft.com/web_api/api.read
redirect_uri: https://localhost:435
code:
code_verifier:
The thing is I get the token but while calling the web api, it's giving error like:
Either scp or roles claim need to be present in the token
What could be the problem?
I tried to reproduce the same in my environment and got below results:
I registered one Azure AD B2C application for Web API and added scopes as below:
Now I created one SPA registration and added API permissions by granting consent like this:
I created Sign up and sign in policy and ran the user flow as below:
When I signed-in as a user it gave me auth-code in address bar like below:
I generated the access token via Postman with parameters like this:
POST https://tenant.b2clogin.com/tenant.onmicrosoft.com/policy/oauth2/v2.0/token
grant_type: authorization_code
client_id: SPA_appid
scope: https://tenant.onmicrosoft.com/web_api/api.read
redirect_uri: redirect_uri
code: code
code_verifier: code_verifier
When I decoded the token, I got the scp claim successfully like below:
Make sure to select Application as SPA App and resource as Web_api while running the user flow to get auth code.
While generating access token, you should give SPA_AppId in client_id parameter.
I have Keycloak for authentication and authorization of multiple applications (a web page and a REST API). From my understanding the flow for the web page when using OAuth2 authentication_code grant type is as follows:
In this flow, in the second step (the one in red) the resource owner logs in because she/he were redirected to the login page of Keycloak. This flow is clear to me and is working well.
But, with the REST API I don't know what is the process to authenticate and authorize the user (resource owner), because there isn't a browser to redirect him to the login page of Keycloak. So, I tried with the password grant type and it worked, but then I realized that this grant type is deprecated. So I tried again with the authorization_code grant type but can't make it work. I am trying to get the token using the following request:
URL: http://localhost:8080/auth/realms/somerealm/protocol/openid-connect/token
Body:
username: someuser
passwoord: somepassword
grant_type: authorization_code
client_id: someclient
secret: somesecret
The problem is that I am receving the following response:
{
"error": "invalid_request",
"error_description": "Missing parameter: code"
}
I know I have something wrong in the request (and in my understanding of OAuth2), but I have read a lot and can't discover what it is.
API (backend) doesn't need any login flow usually. It just needs to verify token and then it executes requested operation or it denies it (response code 401 - problem with authentication / 403 - problem with authorization). It doesn't redirect to auth server.
Client, which is using API must obtain token before API request. It can be done by the frontend (e.g. SPA with The Authorization Code Flow + PKCE) and then frontend maintains state (token refresh, error codes from the API, ...).
If you don't have any frontend, then procedure how to get token must be part of API specification. For example see swagger doc: https://swagger.io/docs/specification/authentication/oauth2/
The Client credentials flow should be used machine to machine authentication, so it's not a solution if you need to know user identity.
With the authorization_code grant type you have to spawn a browser in some way.
password is unfortunately deprecated, but the recommendation is to use client_credentials for these cases now. I hope this decision get reversed before OAuth 2.1 is released.
I have setup a Cognito user pool so that I can use it to authorize access the an api gateway. It uses OAUTH2 and the flow im using is : Authorization Code Grant,
Scopes : email, openid and profile,
Allowed Custom Scope : product-api/read_product, product-api/create_product, product-api/delete_product
I use boto3 admin_initiate_auth command to connect to the user pool:-
response = idpclient.admin_initiate_auth(
UserPoolId=USERPOOLID,
AuthFlow='ADMIN_NO_SRP_AUTH',
AuthParameters={
'USERNAME':USERNAME,
'PASSWORD':PASSWORD,
'SECRET_HASH':SECRET_HASH
},
ClientId=APPCLIENTID
)
and the response I receive is a json object with several fields, which include access_token, refresh_token etc...
but when I use the access_token to access the api gateway, i get a 401 error. Unauthorised. Looking into the access_token it looks like the custom scopes have not been added.
Could you advise why the custom scope has not been added to the access_token and how do i get the custom scopes added ?
the api gateway has a lambda authorizer added.
Usually you have to specify the Scopes in 2 places:
The OAuth client entry for the client application in the Cognito section of the AWS console
The code requesting a token - I have always implemented this in a standards based manner whereas you are using an AWS specific solution
Looks like what you want may not be supported via admin_initiate_oauth:
Include user details in AWS Cognito Oauth2 token
If your client application is a web UI then the standards based solution will do what you want.
I've tested my Cognito single page app sample with custom scopes - you can run it here:
https://authguidance.com/home/code-samples-quickstart
Not sure if this type of solution will work for you though ..
How do you create a seamless login flow for a single page application using third party open id connect provider (such as Google or Microsoft) that then generates a new jwt token from an existing one returned by the external provider without refreshing the page?
For example, I want a user to be able to log into Google, then be brought back to my site where I validate the token server side using IdentityServer4, then extract certain claims and generate a new JWT (my own logic).
Is there an existing IdentityServer4 endpoint that validates JWT tokens from Open Id Providers at the redirect and then what's the best approach to injecting my own token creation flow afterwards? The end result is a ideally a cookie containing my new JWT token that will now be sent on every http request my SPA makes.
My best guess is to use the oidc js client and set up a user manager for Google, for example:
var mgr = new Oidc.UserManager({
authority: "https://accounts.google.com/.well-known/openid-configuration",
client_id: "---",
redirect_uri: "http://localhost:60720/account/callback",
response_type: "id_token token",
scope: "openid profile email",
post_logout_redirect_uri: "http://localhost:60720/spa",
});
/*...*/
mgr.signinRedirect();
However, on the redirect, I need Google to send a cookie to my controller, which will then use IdentityServer to validate the token, extract some claims like the user id, and then generate a new token for my API. This assumes I'm using IdentityServer to host my own identity provider. How do I use IdentityServer4 to accomplish this last part?
This is simple to do with an MVC pattern because the token is generated on the post back after the redirect callback is invoked. In a SPA, there should be minimal redirection, ideally none where a popup is displayed to allow the user to login and then the SPA takes over. I've been unable to figure out how to redirect from an external identity provider to my IdentityServer4 auth server or MVC server and generate a new token with minimal disruption of the de-facto configuration.
Google recommends that the server must validate the token (https://developers.google.com/identity/protocols/OAuth2UserAgent#validate-access-token). One possible solution is to generate my new token in the redirect callback after its validated. However, isn't IdentityServer4 supposed to validate the token, or do I have to do this myself on the server? What part does IdentityServer4 play here in the token validation. I don't want to hand code this step myself.
I ended up creating my own grant type with an Identity Server endpoint just to exchange a third party authentication cookie into an internal JSON-bearer based token.
I have created OAuth 2.0 Playground access tokens using the following info:
Select & Authorize APIs: https://www.googleapis.com/auth/consumersurveys https://www.googleapis.com/auth/userinfo.email
GET https://www.googleapis.com/consumersurveys/v2/surveys
This works (for me it returns a list of surveys I had created previously).
However, when I create access tokens using Postman OR retrieve them from AspNetUserClaims table those access tokens don't work.
Example #1: I get an access token in Postman for Google and add it to the Header (a checkmark appears for Bearer and token). I press Send in Postman and it returns "Invalid_Credentials". In case the token is expired or invalid, I delete it and create a new one to use in the header. Still fails.
POSTMAN info:
Auth URL: https://accounts.google.com/o/oauth2/auth
Access Token URL: https://accounts.google.com/o/oauth2/token
Client ID: hidden
Client Secret: hidden
Scope: https://www.googleapis.com/auth/userinfo.email
Grant Type: Authorization Code
Request access token locally is checked.
Example #2: I use the Google Sign-On button on my dev site which generates an access token that is then stored in the AspNetuserClaims table. I copy that access token into Postman (a checkmark appears also) and press Send and it also returns "Invalid_Credentials". In case the token is expired, I delete the newly created account and access token from all the AspNet user tables and try it again. Still fails.
Why is this only working with OAuth 2.0 Playground tokens in Postman? They are all newly generated tokens through the Postman token wizard or newly registered user accounts or the OAuth2.0 Playground wizard, but only the OAuth2.0 Playground tokens actually work...
Figured this out.
I believe the issue was that the access token in Postman required more scopes to authenticate me fully, which makes sense since this API contains surveys that I am trying to access, which are also linked to a Google account. This started working only after I added the consumersurveys.readonly scope (using A SPACE) along with the userinfo.email scope, as outlined below.
This SCOPE SETTING alone didn't work:
https://www.googleapis.com/auth/userinfo.email
This SCOPE SETTING with more permission to this API DID work!
https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/consumersurveys.readonly
More info on adding scopes to C# code can be found here: http://www.oauthforaspnet.com/providers/google/
Hope this helps anyone else out there who runs into a similar issue.