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

feat: forward signIn auth params to /authorize #1149

Merged
merged 4 commits into from
Jan 18, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/client/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ const _useSessionHook = (session) => {
}

// Client side method
export const signIn = async (provider, args = {}) => {
export const signIn = async (provider, args = {}, authorizationParams = {}) => {
const baseUrl = _apiBaseUrl()
const callbackUrl = args.callbackUrl ?? window.location
const providers = await getProviders()
Expand All @@ -257,6 +257,7 @@ export const signIn = async (provider, args = {}) => {
},
body: _encodedForm({
...args,
authorizationParams,
csrfToken: await getCsrfToken(),
callbackUrl: callbackUrl,
json: true
Expand Down
23 changes: 14 additions & 9 deletions src/server/lib/signin/oauth.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,25 @@ import oAuthClient from '../oauth/client'
import { createHash } from 'crypto'
import logger from '../../../lib/logger'

export default async function oauth (provider, csrfToken) {
const { callbackUrl } = provider
export default async function getAuthorizationUrl (req) {
const { provider, csrfToken } = req.options

const client = oAuthClient(provider)
if (provider.version?.startsWith('2.')) {
// Handle OAuth v2.x
let url = client.getAuthorizeUrl({
redirect_uri: callbackUrl,
...provider.authorizationParams,
...req.body.authorizationParams,
redirect_uri: provider.callbackUrl,
scope: provider.scope,
// A hash of the NextAuth.js CSRF token is used as the state
state: createHash('sha256').update(csrfToken).digest('hex'),
...provider.authorizationParams
state: createHash('sha256').update(csrfToken).digest('hex')
})

// If the authorizationUrl specified in the config has query parameters on it
// make sure they are included in the URL we return.
//
// This is a fix for an open issue with the oAuthClient library we are using
// This is a fix for an open issue with the OAuthClient library we are using
// which inadvertantly strips them.
//
// https://github.com/ciaranj/node-oauth/pull/193
Expand All @@ -28,14 +30,17 @@ export default async function oauth (provider, csrfToken) {
url = url.replace(baseUrl, provider.authorizationUrl + '&')
}

logger.debug('GET_AUTHORIZATION_URL', url)
return url
}

try {
const oAuthToken = await client.getOAuthRequestToken(callbackUrl)
return `${provider.authorizationUrl}?oauth_token=${oAuthToken}`
const oAuthToken = await client.getOAuthRequestToken(provider.callbackUrl)
const url = `${provider.authorizationUrl}?oauth_token=${oAuthToken}`
logger.debug('GET_AUTHORIZATION_URL', url)
return url
} catch (error) {
logger.error('GET_AUTHORISATION_URL_ERROR', error)
logger.error('GET_AUTHORIZATION_URL_ERROR', error)
throw error
}
}
9 changes: 4 additions & 5 deletions src/server/routes/signin.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import oAuthSignin from '../lib/signin/oauth'
import getAuthorizationUrl from '../lib/signin/oauth'
import emailSignin from '../lib/signin/email'
import logger from '../../lib/logger'

Expand All @@ -9,8 +9,7 @@ export default async function signin (req, res) {
baseUrl,
basePath,
adapter,
callbacks,
csrfToken
callbacks
} = req.options

if (!provider.type) {
Expand All @@ -19,8 +18,8 @@ export default async function signin (req, res) {

if (provider.type === 'oauth' && req.method === 'POST') {
try {
const oAuthSigninUrl = await oAuthSignin(provider, csrfToken)
return res.redirect(oAuthSigninUrl)
const authorizazionUrl = await getAuthorizationUrl(req)
return res.redirect(authorizazionUrl)
} catch (error) {
logger.error('SIGNIN_OAUTH_ERROR', error)
return res.redirect(`${baseUrl}${basePath}/error?error=OAuthSignin`)
Expand Down
2 changes: 1 addition & 1 deletion www/docs/errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ These errors are displayed on the terminal.

### Signin / Callback

#### GET_AUTHORISATION_URL_ERROR
#### GET_AUTHORIZATION_URL_ERROR

#### SIGNIN_OAUTH_ERROR

Expand Down
19 changes: 19 additions & 0 deletions www/docs/getting-started/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,25 @@ e.g.

The URL must be considered valid by the [redirect callback handler](/configuration/callbacks#redirect). By default it requires the URL to be an absolute URL at the same hostname, or else it will redirect to the homepage. You can define your own redirect callback to allow other URLs, including supporting relative URLs.

#### Additional params

It is also possible to pass additional parameters to the `/authorize` endpoint through the third argument of `signIn()`.

See the [Authorization Request OIDC spec](https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest) for some ideas.

e.g.

* `signIn("identity-server4", null, { prompt: "login" })` *always ask the user to reauthenticate*
* `signIn("auth0", null, { login_hint: "info@example.com" })` *hints the e-mail address to the provider*

:::note
You can also set these parameters through [`provider.authorizationParams`](/configuration/providers#oauth-provider-options).
:::

:::note
The following parameters are always overridden: `redirect_uri`, `scope`, `state`
:::

---

## signOut()
Expand Down