Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set oAuth redirect URL dynamically #1591

Closed
fadiquader opened this issue Sep 30, 2019 · 14 comments
Closed

Set oAuth redirect URL dynamically #1591

fadiquader opened this issue Sep 30, 2019 · 14 comments
Labels

Comments

@fadiquader
Copy link
Contributor

Steps to reproduce

I'm working on a project where I need to set the oAuth redirect URL dynamically (I need to set the domain or subdomain dynamically). I've read that this is possible in the latest version of Feathers (#990). However, I've struggled to make this work in practice. Looking at the code, it seems that it is not possible to dynamically set the redirect URL -- what I see in the code here just uses the redirect URL from the environment variables: https://github.com/feathersjs/feathers/blob/master/packages/authentication-oauth/src/strategy.ts#L75

Expected behavior

I'd like to be able to dynamically set the redirect URL, changing the domain or subdomain. This seems to be possible with Grant directly, but I can't see how to do this with Feathers.

Actual behavior

I can't see any way to do this! Would really appreciate your advice on how to do this (if it's possible)

System configuration

Tell us about the applicable parts of your setup.

Module versions (especially the part that's not working):
Feathers v4 (latest)

@daffl
Copy link
Member

daffl commented Sep 30, 2019

All methods can be easily customized by overriding them in your own class which is documented here and also shown with a GitHub login in the guide. In your case by overriding the getRedirect method you linked to:

class MyDynamicRedirectStrategy extends OAuthStrategy {
  async getRedirect(authResult) {
    const { user } = authResult;
    // Get the redirect url e.g. from the users organization
    const { redirectUrl } = await app.service('organizations').get(user.organizationId);
    // This is necessary if it should work with the standard Authentication
    // client (which could be customized as well)
    const query = authResult.accessToken ? {
      access_token: authResult.accessToken
    } : {
      error: data.message || 'OAuth Authentication not successful'
    };

    return `https://${redirectUrl}#${querystring.stringify(query)}`;
  }
}

// ...
authentication.register('github', new MyDynamicRedirectStrategy());

@fadiquader
Copy link
Contributor Author

@daffl
Thank you for getting back, what I mean is by accessing req.query for example so I’m unable to access the req object, because i want to set it dynamically by querying backend.

@daffl
Copy link
Member

daffl commented Oct 1, 2019

I'm assuming this is what Grants dynamic overrides are for.

@fadiquader
Copy link
Contributor Author

@daffl
I've tried that many times but it didn't work!
Thank you so much for your help!

@daffl daffl added the Bug label Oct 1, 2019
@daffl
Copy link
Member

daffl commented Oct 1, 2019

Got it. This is probably a bug since the bodyParser is missing and the URL hasn't been documented yet. This is probably also the same issue as in #1387.

@daffl
Copy link
Member

daffl commented Oct 1, 2019

What provider is this and what redirect URL do you want to set?

@fadiquader
Copy link
Contributor Author

@daffl
I'm using Google provider, if i can override getRedirect by accessing context.params.query as i'm using hooks, then i can change redirectURL based on my the incoming request, because i have 2 different domains!, so my problem would be solved, but I'm not sure if i'd be able to do that!
If you have an idea in your mind for redirecting users based on the incoming requests, it would be great!

async getRedirect(authResult, params) {
    // const { redirectUrl } = params.query // not real! 
    const { user } = authResult;
    const query = authResult.accessToken ? {
      access_token: authResult.accessToken
    } : {
      error: data.message || 'OAuth Authentication not successful'
    };
    return `https://${redirectUrl}#${querystring.stringify(query)}`;
  }

@daffl
Copy link
Member

daffl commented Oct 3, 2019

Ok, that makes sense. Probably means the rest of the query in https://github.com/feathersjs/feathers/blob/master/packages/authentication-oauth/src/express.ts#L34 needs to be stored in the session and then passed as params.query to authenticate and getRedirect.

@green3g
Copy link

green3g commented Nov 14, 2019

Question (from slack):

Lets say I have multiple javascript apps (each on different domains). How can I have each of them redirect correctly but re-use existing oauth providers, like lets say I want to have app1.domain.com and app2.domain.com both be able to login to my app through google oauth.

Consider this:

CustomOauthProvider.js:

async getRedirec(authResult, params){
    const url = prams.redirect;
    const validAppService = this.app.service('apps');
    const appConfig = await validAppService.find({ url })[0];
    
    if(!url){
        throw new Error('this is not a valid redirect')
    }

    return url;
}


// another scenario
async getRedirec(authResult, params){
    const appId = prams.appId;
    const validAppService = this.app.service('apps');
    const appConfig = await validAppService.find({ appId })[0];
    
    if(!appConfig){
        throw new Error('this is not a valid appId')
    }
    // additional logic might check to see if user can login to this app

    return appConfig.redirect;
}

@green3g
Copy link

green3g commented Jan 25, 2020

Just revisiting this a little bit - I think this is sort of what I'd like to do with my feathers/client apps ->
https://www.oauth.com/oauth2-servers/redirect-uris/redirect-uri-validation/

basically register an application and its redirect URI - it could be a custom uri scheme or a different domain based url, like
my-android-app://?token=xxx
my.domain.com/redirect?token=xxx
...

I don't believe this would currently work, it looks like it only works with paths on the same domain. Would that be something that feathers could work with? I could take a stab at a pull request.

@daffl
Copy link
Member

daffl commented Jan 25, 2020

You can already do this by passing the additional information through the flow via the redirect parameter and customizing getRedirect method which is what ultimately redirects to your frontend.

This issue can also be closed, since it is now possible by setting the redirect query parameter.

@daffl daffl closed this as completed Jan 25, 2020
@m0dch3n
Copy link

m0dch3n commented Feb 5, 2020

@daffl

I have my app on https://app.somedomain.com and my feathers on https://sync.somedomain.com.

When I directly access https://sync.domedomain.com/oauth/google with address the bar from the browser, my oAuth flow is working, I get authenticated, it creates and updates the user in the database and I can redirect the user to my app with

  class GoogleStrategy extends OAuthStrategy {
    async getRedirect (data) {
      const appURL = app.get('appURL')
      return `${appURL}#accessToken=${data.accessToken}&strategy=${data.authentication.strategy}`
    }
...

So I'm able log him in, with accessToken.

In my default.json, I have the following config:

    "oauth": {
      "redirect": "https://sync.somedomain.com/",
      "google": {
        "key": "SOMEKEY",
        "secret": "SOMESECRET",
        "scope": [
          "email",
          "profile",
          "openid"
        ]
      },

However
When I now put a link, on my app

<a href="https://sync.somedomain.com/oauth/google" rel="noreferrer">Login with Google</a>

I receive an error from Google:

`Error: redirect_uri_mismatch

The redirect URI in the request, https://app.somedomain.com/oauth/google/callback, does not match the ones authorized for the OAuth client.`

So it seems, in this case to use the referrer and not the data from the default.json file. rel="noreferrer" also does not have any effect...

@daffl
Copy link
Member

daffl commented Feb 5, 2020

There are two different redirect URLs. The redirect is the location of your frontend. The oauth redirect is the hostname of the server. This is usually put together by the host setting in the configuration which in your case appears to be set to app.somdeomain.com instead sync.somedomain.com where it is running.

@m0dch3n
Copy link

m0dch3n commented Feb 5, 2020

thank you, to clarify this, I'm very new to oauth, so maybe I'm doing something wrong...

The host in default.json actually is 0.0.0.0 and port is 3030 because my feathers is running in a docker container, behind a proxy...

app.somedomain.com does not exist anywhere in my feathers code, so I really don't understand why feather is setting this as redirect uri, when I click on the link... This is why I supposed it must be related to the refererrer somehow...

So if understand correctly, usually the redirect is constructed with the host information from default.json? I'll try to investigate then, in this direction...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants