aws-amplify / amplify-js

A declarative JavaScript library for application development using cloud services.
https://docs.amplify.aws/lib/q/platform/js
Apache License 2.0
9.41k stars 2.11k forks source link

Allow OAuth 2.0 Authorization Code Grant flow via a custom UI (Single-Sign-On, SSO) #6236

Open davidgengenbach opened 4 years ago

davidgengenbach commented 4 years ago

Is your feature request related to a problem? Please describe. I would like to authenticate via Cognito and Amplify Auth - and provide a "third-party" app access via a OAuth Authorization code.

While I use the normal Auth.signIn(...) approach to receive Access- and Id-Tokens (which works fine), I also need to receive a Code via the OAuth 2.0 Authorization Code Grant flow with PKCE to pass to another application - thereby enabling Single-Sign-On (SSO).

The user is authenticated using a username/password using SRP and with optional MFA. This works fine and the Access- and Id-Tokens are correctly set by Amplify.

Describe the solution you'd like The Amplify API could provide way a way to get the Authorization Code after a successful authentication.

Describe alternatives you've considered While the hosted UI provides the functionality out-of-the-box, it is not an alternative for our use-case. Writing custom OAuth flow code as described here is also out of scope since it is too low-level, does not integrate with Amplify and is not easily extendible to use MFA. Implicit grants are not an alternative as well.

yash-kalwani commented 3 years ago

i have spend hours researching this and initially i thought i might be missing out on some documentation on how to implement the Authorisation code grant flow without the hosted UI but it seems this is a legit issue ( ?? )

When i use the Auth.signIn(...) function with only Authorization code grant flow enabled on the app client i receive the access token, id token and refresh token. What i was expecting is a one time code that can then be exchanged for tokens on the oauth/token endpoint.

The docs are very vague in this matter, am i missing out on something here?

debugguru commented 3 years ago

We are looking for similar functionality. Our use case is enable Alexa skill from our app as documented here https://developer.amazon.com/en-US/docs/alexa/account-linking/app-to-app-account-linking-starting-from-your-app.html

To call the skill api in last step we need to reterive authorisation code for logged in user https://developer.amazon.com/en-US/docs/alexa/account-linking/app-to-app-account-linking-starting-from-your-app.html#how-it-works

Any update on how this can be done with Auth library from with the mobile app?

jglesner commented 3 years ago

+1

willianantunes commented 2 years ago

Sadly I had to drop the idea of using Cognito because it does not support the Authorization Code grant type through its API. I even thought it was possible to create a wrapper incorporating this responsibility. Still, it turns out it would be problematic, as the SDK does not have the customized Scope or OAuth Scopes, e.g., email, profile, etc., in the user's access token 😑.

I've made this project to test the possibilities.

claudiopastorini commented 2 years ago

Thanks @willianantunes for your work, you save me a lot of hours... Waiting for this feature

willianantunes commented 2 years ago

Hi everyone! I've made a blog post explaining how to do SSO (single sign-on) with Cognito. All the code can be consulted here, including the functional tests. I explain there the limitations of Cognito UI, including the one we discussed in this issue.

andrew-haus commented 2 years ago

+1 Spent hours of research thinking theres a way to do this since Amplify seems to say they support auth code grant but finally got pointed to this issue here.

stangatimu commented 2 years ago

@andrew-haus found anything yet

andrew-haus commented 2 years ago

@stangatimu I reached out to AWS support and this is a snippet of what they sent.

I got an update from the internal team. They've confirmed that at present this feature is not supported by Amplify IOS.

Your use case is currently a feature request with amplify.

[+] https://github.com/aws-amplify/amplify-js/issues/6236

Basically pointing me to where I've been. So no luck.

elorzafe commented 2 years ago

Is possible to implement SSO when using Auth.federatedSignIn on all of your apps.

Steps to configure

  1. On Cognito Hosted UI configuration you add multiple callback URLs (Callback URL(s), and Sign out URL(s)), one for each App you want to enable SSO, e.g. https://myapp1.com/, https://myapp2.com/
  2. On each App that you want to integrate specify your App Url, e.g. Auth configuration for myapp1.com would be like this:
    oauth: {
            domain: 'your_cognito_domain',
            scope: ['phone', 'email', 'profile', 'openid', 'aws.cognito.signin.user.admin'],
            redirectSignIn: 'https://myapp1.com/',
            redirectSignOut: 'https://myapp1.com/',
            responseType: 'code' 
        }

and for myapp2.com like this:

oauth: {
            domain: 'your_cognito_domain',
            scope: ['phone', 'email', 'profile', 'openid', 'aws.cognito.signin.user.admin'],
            redirectSignIn: 'https://myapp2.com/',
            redirectSignOut: 'https://myapp2.com/',
            responseType: 'code' 
        }
  1. Use Auth.federatedSignIn() on each App, and SSO will be enabled.
plittlewood-rpt commented 2 years ago

This won't work for us unfortunately because our app clients are registered by third party developers (and we have hundreds all with different redirect URIs). It wouldn't be feasible or manageable to have all apps with the same redirect URIs

Ragul29 commented 1 year ago

Any update or work-around to solve this issue?

Ragul29 commented 1 year ago

Just try to bypass the cognito Hosted Ui or Use Oauth sign in:

Bypassing the cognito Hosted Ui: There is no other way to get pkce authorization code from cognito without using hosted ui. since you have mentioned your flow was SRP with optional mfa, there is a workaround which i have tried, You can create a backend API or serverless lambda function while user try to login with username and password in your custom login page with Auth.Signin() amplify function cognito will return the CognitoUser object as a response, after you get the successful response you can call your api by passing username and password as param, where you are going to make a http request to cognito by calling oauth2/authorize (with necessary query params) endpoint, that will return the XSRF-TOKEN as cookies, you are going to capture that cookie response and then you have to make a /login post request to cognito by passing the XSRF-TOKEN with form data as username and password, you will get the callback url from cognito with authorization code as response. you can store the code for exchanging the token later by making a post request to oauth2/token endpoint.

Note: if user enabled mfa, this flow won't work. you can disable the mfa using amplify Auth.Setpreferredmfa(nomfa) before make an api call, later you can enable the mfa with preferred mfa.

So using cognito custom login (amplify lib), user can login to their app and get the authorization code as well. the app can grant access to other app's by exchanging the pkce code

Oauth Sign in: if oauth sign in is enabled, the users will be redirected by federation sign in option, they will be authorized and rewarded with pkce code and state, application tries to consume the code. once single sign on enabled after the first successful login attempt, you can redirect back to the authorize cognito endpoint to capture the pkce code and state value (shouldn't intialize the Auth.Configure() function since this function will try to consume the pkce code) and you can store the values somewhere in DB, later you can call the token cognito endpoint to get the token.

let me know if you have any issue with the above mentioned workaround

Thanks Ragul

Ragul29 commented 1 year ago

Is your feature request related to a problem? Please describe. I would like to authenticate via Cognito and Amplify Auth - and provide a "third-party" app access via a OAuth Authorization code.

While I use the normal Auth.signIn(...) approach to receive Access- and Id-Tokens (which works fine), I also need to receive a Code via the OAuth 2.0 Authorization Code Grant flow with PKCE to pass to another application - thereby enabling Single-Sign-On (SSO).

The user is authenticated using a username/password using SRP and with optional MFA. This works fine and the Access- and Id-Tokens are correctly set by Amplify.

Describe the solution you'd like The Amplify API could provide way a way to get the Authorization Code after a successful authentication.

Describe alternatives you've considered While the hosted UI provides the functionality out-of-the-box, it is not an alternative for our use-case. Writing custom OAuth flow code as described here is also out of scope since it is too low-level, does not integrate with Amplify and is not easily extendible to use MFA. Implicit grants are not an alternative as well.

The workaround which I have tried https://github.com/aws-amplify/amplify-js/issues/6236#issuecomment-1496379648

justinffortier commented 1 year ago

@Ragul29 I have tried your workaround, but am getting stuck at the point at which I try to post to the /oauth2/login endpoint

Here is my request... What am I missing?

curl --location 'https://{mycognito-pool}.us-west-1.amazoncognito.com/oauth2/login' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Cookie: XSRF-TOKEN={XSRF-TOKEN}; csrf-state=""; csrf-state-legacy=""' \
--data-urlencode 'username={username}' \
--data-urlencode 'password={password}' \
--data-urlencode '_csrf={XSRF-TOKEN}'

I basically looked at how the hosted UI formats it's post in order to fill in some of the blanks

I am getting 405 Method Not Allowed

Ragul29 commented 1 year ago

Hi @justinffortier ,

Could you please change the post endpoint to https://{mycognito-pool}.us-west-1.amazoncognito.com/login and try again?

Attaching the sample code for your reference,

Please try to send the exact query params and form data as body of the post request with obtained XsrfToken.

// Post CSRF Token and username/password to /login endpoint var codeRequestUrl = https://${AUTH_DOMAIN}/login?response_type=${RESPONSE_TYPE}&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT_URI};

form = {
  '_csrf': `${XSRFTOKEN}`,
  'username': `${USERNAME}`,
  'password': `${PASSWORD}`,
}

var formData = querystring.stringify(form);
var contentLength = formData.length;

request({
  headers: {
    'Content-Length': contentLength,
    'Content-Type': 'application/x-www-form-urlencoded',
    'Cookie': `${XSRFTOKEN}`,
  },
  uri: codeRequestUrl,
  body: formData,
  method: 'POST'
}, function (err, res, body) {
  var authorizationCodeGrant = res.headers.location.split('=')[1];
  console.log(authorizationCodeGrant);
});
Valdeminas commented 11 months ago

Any progress or ETA for this?

mikhin commented 8 months ago

Is possible to implement SSO when using Auth.federatedSignIn on all of your apps.

Steps to configure

  1. On Cognito Hosted UI configuration you add multiple callback URLs (Callback URL(s), and Sign out URL(s)), one for each App you want to enable SSO, e.g. https://myapp1.com/, https://myapp2.com/
  2. On each App that you want to integrate specify your App Url, e.g. Auth configuration for myapp1.com would be like this:
oauth: {
            domain: 'your_cognito_domain',
            scope: ['phone', 'email', 'profile', 'openid', 'aws.cognito.signin.user.admin'],
            redirectSignIn: 'https://myapp1.com/',
            redirectSignOut: 'https://myapp1.com/',
            responseType: 'code' 
        }

and for myapp2.com like this:

oauth: {
            domain: 'your_cognito_domain',
            scope: ['phone', 'email', 'profile', 'openid', 'aws.cognito.signin.user.admin'],
            redirectSignIn: 'https://myapp2.com/',
            redirectSignOut: 'https://myapp2.com/',
            responseType: 'code' 
        }
  1. Use Auth.federatedSignIn() on each App, and SSO will be enabled.

this worked for me, huge thanks

ashwinchandran13 commented 7 months ago

@Ragul29 getting a CORS error on requesting to /oauth2/authorize endpoint to get XSRF Token in cookies to call login endpoint. How did you get past CORS?

Ragul29 commented 7 months ago

@Ragul29 getting a CORS error on requesting to /oauth2/authorize endpoint to get XSRF Token in cookies to call login endpoint. How did you get past CORS? Could you please post the response headers info, from where you are trying to access?

ashwinchandran13 commented 6 months ago

@Ragul29 getting a CORS error on requesting to /oauth2/authorize endpoint to get XSRF Token in cookies to call login endpoint. How did you get past CORS? Could you please post the response headers info, from where you are trying to access?

@Ragul29 Dropped the idea to call the cognito hosted URL from client but did use request package to call it from backend. Passed XSRF-TOKEN in orderly fashion i.e. from auth enpoint(GET) -> login enpoint (POST). The problem is eventhough XSRF-TOKEN is achieved till the end of step, 302 is returned without code appended to URL. Also tried with MFA enabled.