SkygearIO / features

Feature Tracking Repo for Skygear
Apache License 2.0
3 stars 12 forks source link

Authorization + Security Setting page for Users #370

Open chpapa opened 4 years ago

chpapa commented 4 years ago

Description

Support an end-point for login/signup + security setting which users can use directly for their web / mobile apps.

The experience should be similar with how Google different product support the same login and security setting page, or Auth0's Universal Login

Features:

Other feature:

Portal Design

Blog Post Specification

Blog Post of the Feature Release

Open Questions

Related Issues

louischan-oursky commented 4 years ago

Moved the discussion from Basecamp to here.


Ben wrote

Thanks Ten Tang Ten I think it provide some useful insights, here are some of my response. I will add some of these to Github Feature Issue so Louis Chan Louis could take reference too.

  • Username and Password in two steps
    • I think it is preferred to have username and password in two pages, as it provides the opportunities in UX, for Skygear to determine what type of login it is. Some login type may require a different flow (e.g. SAML?)
  • User should be able to add custom signup form fields such as First Name and Last Name to metadata
    • I think this is an interesting idea, maybe can't have it on phase 1 but seems nice to make it possible to configure custom fields at Sign up form and as you said, put them in MetaData of the signed up user
  • Show the requirements of the password like Nvidia Design
    • Agree, I think that is something we should ask Frank to address on the design
  • The Terms & Condition Popup
    • I think we can only accommodate it with HTML template customization (and a good use case) We’ll ask the user to login again after verifying their email. It’s a more secure practice. Is that okay? Actually, we won't ask the user to login "again", they just need the sessions to verify the email, and if they don't have it will be asked to login again

Louis wrote

  • The detection of login ID type requires JavaScript. Even we detect in Auth UI server side, both phone numbers and username can consist of only digits and it is ambiguous.
  • We cannot support "Keep me signed in" checkbox. Auth Gear currently does not support session cookie. I mean the session cookie as opposed to persistent cookie. The one that got wiped by the browser when you close the browsing window. The session is always persistent.
  • Can we drop "Account created" screen after signup? Technically speaking, the end result is authentication success so we should redirect immediately as we do for login case. Creating an extra screen complicates the flow.
  • The "Show Password" requires JavaScript. We can make the page progressive. If JavaScript is enabled, then this button is shown. This also applies to other features that require JavaScript, like the dynamic fulfillment detection of password requirements as the user types.
  • Back button requires JavaScript. The user can just go back with their browser back button. Can we simply drop this?
  • It is possible to generate the list of password requirements from AppConfiguration. Though JavaScript is to required to tell the user which requirement is fulfilled as they type.
  • The verification step is a bit tricky. Auth Gear does not really care about the verification state of the user. Should this be a feature of Auth Gear or Auth UI? I mean if it is a feature of Auth Gear, then many APIs of Auth Gear should require verification (say, logically the user must be verified before they can register MFA device). The SDK should be able to handle this extra step in the same way we do with MFA.

Ben wrote

Louis Maybe we should move this to another thread or Github....

Anyway, let me respond quickly below to sync our thinking first.

  • The detection of login ID type requires JavaScript. Even we detect in Auth UI server-side, both phone numbers and username can consist of only digits and it is ambiguous.
    • I think we can do it at the server side, we probably need a smart way to detect it -- depends on if the configuration of LoginID contains username/phone/emails... If not everything is enabled, we can change the help text accordingly
    • We can also give an optional parameter, so developers can specify whether they want a login screen with specific login ID type or not.
    • The same ambiguous can happens for someone use email address as their username? So we will need some sort of "try and error" algo in our login already. I thought we already have (at least some of it?) in our API of login without specifying login ID key?
  • We cannot support "Keep me signed in" checkbox. Auth Gear currently does not support session cookie. I mean the session cookie as opposed to persistent cookie. The one that got wiped by the browser when you close the browsing window. The session is always persistent.
    • Ok. So we are ALWAYS keep me signed in.
    • We don't need it now but just want to know how difficult it is to add it in future? I'm worry we will run into a client have a security policy to prevent persistent cookie in say public computer.
  • Can we drop "Account created" screen after signup? Technically speaking, the end result is authentication success so we should redirect immediately as we do for login case. Creating an extra screen complicates the flow.
    • Seems make sense, but can you just in case double check with other implementation like auth0 or google to see how it works?
  • The "Show Password" requires JavaScript. We can make the page progressive. If JavaScript is enabled, then this button is shown. This also applies to other features that require JavaScript, like the dynamic fulfillment detection of password requirements as the user types.
    • Agree. Actually if making the page works without Javascript is too much effort, forget about it for now. It is okay to assume browsers have JS enabled these days. Some UI features will need JS anyway
  • Back button requires JavaScript. The user can just go back with their browser back button. Can we simply drop this?
    • As mentioned above, if it requires some JS is okay. We don't need to have the "no JS" as the requirement.
  • It is possible to generate the list of password requirements from AppConfiguration. Though JavaScript is to required to tell the user which requirement is fulfilled as they type.
    • Okay
  • The verification step is a bit tricky. Auth Gear does not really care about the verification state of the user. Should this be a feature of Auth Gear or Auth UI? I mean if it is a feature of Auth Gear, then many APIs of Auth Gear should require verification (say, logically the user must be verified before they can register MFA device). The SDK should be able to handle this extra step in the same way we do with MFA.
    • May I know what you meant by tricky?
louischan-oursky commented 4 years ago
  • I think we can do it at the server side, we probably need a smart way to detect it -- depends on if the configuration of LoginID contains username/phone/emails... If not everything is enabled, we can change the help text accordingly
  • We can also give an optional parameter, so developers can specify whether they want a login screen with specific login ID type or not.
  • The same ambiguous can happens for someone use email address as their username? So we will need some sort of "try and error" algo in our login already. I thought we already have (at least some of it?) in our API of login without specifying login ID key?

Actually in signup, the developer using SDK has to choose from signupWithEmail, signupWithUsername and the generic signup that requires explicit login ID type. Since Auth UI is generic, the signup screen should have an extra screen at the beginning. This screen will render a list of login ID buttons according to the configuration of login ID. By default it should render something like

|---------------------------|
| Sign up with email        |
|---------------------------|
| Sign up with phone        |
|---------------------------|
| Sign up with username     |
|---------------------------|

The user have to choose the type and the next screen will display type specific UI for each login ID type. If the app only allows email or phone, then the developer just needs to edit login ID configuration.

I guess the login screen should be similar to the signup screen. It should render something like

|---------------------------|
| Login with Google         |
|---------------------------|
| Login with Facebook       |
|---------------------------|
              Or
|---------------------------|
| Login with email          |
|---------------------------|
| Login with phone          |
|---------------------------|

This design eliminates the need for guessing.


  • Ok. So we are ALWAYS keep me signed in.
  • We don't need it now but just want to know how difficult it is to add it in future? I'm worry we will run into a client have a security policy to prevent persistent cookie in say public computer.

Technically speaking, as long as the user agent is holding the cookie, the cookie should never expire. However, does this mean Auth Gear needs to support stateless session in addition to stateful session?

From the use-case you mentioned, the cookie should still be stateful for security purpose.

So I guess it should be a new option of cookie transport, to tell Auth Gear whether to write a persistent cookie.

Say the developer wants to expire the session after 5 minute of inactivity They can follow this configuration

The developer also want the user agent to forget the cookie as soon as possible. Auth Gear just does not specify the cookie attribute Expires: to make it a session cookie.

In this case the cookie will either be forgot by the user agent or be considered as expired by Auth Gear, whichever comes first.

@kiootic Any thoughts?

But the above mechanism only applies to proper user agents like browsers. Mobile HTTP clients are unaware of the lifecycle of the application. They do not know when to evict session cookies unless the developer tells them to do so.


  • Seems make sense, but can you just in case double check with other implementation like auth0 or google to see how it works?

I just tested and both Auth0 and Google redirect immediately after completing their flow. Of course signing up a new Google account takes a few steps, like filling in your name, birthday and gender. But there is no success screen with a sole button to trigger redirect.


  • Agree. Actually if making the page works without Javascript is too much effort, forget about it for now. It is okay to assume browsers have JS enabled these days. Some UI features will need JS anyway
  • As mentioned above, if it requires some JS is okay. We don't need to have the "no JS" as the requirement.

I will still ensure all major features do not require JavaScript. If JavaScript is required, then the developer would find it very hard to customize the screen. They have to study our template and our JavaScript, try to replicate the behavior on their custom screen.


  • May I know what you meant by tricky?

I mean Auth Gear may need to enforce verification just like it enforces MFA.

Take a look how MFA is handled right now.

If verification is enforced, then the above flow would look like

try {
  await skygear.auth.login("user@example.com", "password");
} catch (e) {
  if (isVerificationRequiredError(e)) {
    // Handle verification before proceeding.
    // Typically the application should redirect the user to verification screen.
  }
  if (isMFARequiredError(e)) {
    // Redirect the user to the MFA screen.
  }
  throw e;
}

We need to introduce a new step verification to Authentication Session

It is a standalone feature and independent of Auth UI. Though Auth UI depends on it.

kiootic commented 4 years ago

I don't think the features would require stateless session? I think most common use case is that, in case user forgot to log out, the session token cookie would not be persisted after closing browser, and the session would expire in a short time (e.g. 1 hour). So the only concern should be how to configure non-persistent session token cookie.

To support 'stay logged in' toggle, we may want to add a parameter (e.g. persistent_session_cookie) in login API endpoint.

chpapa commented 4 years ago

@louischan-oursky Thanks! Responding one by one as follows:

This design eliminates the need for guessing.

But is there any problem with guessing? I would prefer we have better UX and more flexibility here.

For signup, we would have to make users specify which type of login ID they're using. I think we can by default show the UI similar with the current design (show a default login ID type, say email address, and have a link below say "Use a mobile number" / "Use a username instead".)

For login screen, I think in current /login API, login_id_key is optional already? So there are guessing already?

Can we have three configurations as follows?

  1. Signup Screen Type Chooser: Single / List / Default
    • Single Mode: UI Design = Frank's one, but don't display "Use another option"
    • List Mode: UI Design = Louis's proposed one
    • Default Mode: UI Design = Frank's one
  2. Default Signup Login ID Key: [login_id_key]:
    • In Single Mode, it will be the only login ID key accepted
    • In List Mode, it will be the top login ID key on the list
    • In Default Mode, it will be the default login ID key used
  3. Login Screen Type Chooser: Default / List
    • Default Mode = Frank's Design
    • List Mode = Louis' Proposed one

Session cookies

I don't think it is relevant to stateless session or not (Well although if you remember we talked about we will need it one day, but I think that day is still far far away...)

I think if we have "session expiry after inactivity", maybe that would help a bit already...

If I understand you correctly, Skygear now only support permanent cookies; However in HTTP protocol, if we don't state the expiry, cookies by default is session only, which could support the "stay logged in" toggle already.

So more likely is we would just add a parameter on the login API endpoint as @kiootic said

Success Screen

Thanks for double checking!

Javascript

I will still ensure all major features do not require JavaScript. If JavaScript is required, then the developer would find it very hard to customize the screen. They have to study our template and our JavaScript, try to replicate the behavior on their custom screen.

That's lovely, I was worried it is too much of work but you're so considerate HEHEHE

Verification

Noted, that's what I thought too. But I'm not sure why Auth UI depends on it?

My thinking was, it seems okay to assume, if verification email (or sms) is enabled, we can assume the AuthUI wants to verify the user after sign up.

However, what happen if the user not verified, seems not relevant to AuthUI? So AuthUI and our endpoint seems don't need to care if the user is verified or not? (Unlike MFA, coz if MFA is enforced, you don't even want the user to be logged in...)

chpapa commented 4 years ago

@louischan-oursky oh one requirements I forgot! Is multi-lingual support...

A client we are discussing are asking for 英语(English)、越南语(Tiếng Việt)、马来语(Malaysia)、僧伽罗语(Sinhala)、法语(French)、马拉加斯语(Malagasy)、孟加拉语(Bangladeshi)、维语(Uyghur)already lol

louischan-oursky commented 4 years ago

Login ID key and Login ID type

For login screen, I think in current /login API, login_id_key is optional already? So there are guessing already?

We do not have guessing in /login. If the login ID is a phone number, the developer must provide it in E.164 format, for example, +85222334455. This should result in an exact match. So the developer's job is to provide a UI similar to Frank's design, asking the user to input the calling code and the nation number. And then format them in E.164 and send it to /login.

Can we have three configurations as follows?

I prefer we keep this simple and not to introduce many branches in template rendering.

We have two problems to solve.

  1. Disambiguate login ID key in signup screen because login_id_key is required at signup time.
  2. Disambiguate login ID type in login screen because login_id_key is always optional. However, the type affects how we present the UI.

For the first problem, I think we should EITHER implement List mode or Default mode.

List mode is the same as my proposal.

For Default mode, suppose the developer configures 4 login ID keys phone1, phone2, email1 and email2. We would show a phone number input UI because phone1 is the default. And three buttons below saying "Use phone2 instead", "Use email1 instead" and "Use email2 instead".

For the second problem, we should also EITHER implement List mode or Default mode.

For Default mode, this time we want the user to choose from the types. The available types to choose from is phone and email. We would show a phone number input UI because phone1 is the default. And one button below saying Use email or username instead.

If the application only has 1 login ID key configured, then Default mode should have a simpler UI. The user does not need to choose anything.

So I prefer we only implement Default mode.

Verification

My thinking was, it seems okay to assume, if verification email (or sms) is enabled, we can assume the AuthUI wants to verify the user after sign up.

It is possible that the user close the browser after signup without finishing the verification. So the verification check MUST be performed on every authentication, not just after signup.

However, what happen if the user not verified, seems not relevant to AuthUI? So AuthUI and our endpoint seems don't need to care if the user is verified or not? (Unlike MFA, coz if MFA is enforced, you don't even want the user to be logged in...)

I am going talk about some implementation details so please bear with me.

The authentication flow is OAuth Authorization Code flow with PKCE. At the beginning of the flow the application generates Code Verifier and derive Code Challenge from Code Verifier. Finally the application is returned via redirect_uri with a Authorization Code. The application then submit the Authorization Code and the Code Verifier to exchange Access Token. The Authorization Code is consumed and the session is created at this point.

The authorization code should not be reused. We have an issue to track this.

What if we need to add verification step in the flow?

First, we agreed that verification requires authentication in issue 382. So the user must be authenticated to verify. By the time the user lands on the verification screen, the user must be authenticated, otherwise verification never succeed. It means the Authorization Code should have been consumed. We do not have the Authorization Code to deliver back to the application.

@kiootic Thoughts?

i18n

Fortunately the OpenID Connect defines a query parameter ui_locales exactly for this purpose. And our template mechanism is designed with i18n support. Supporting multiple languages should be possible.

kiootic commented 4 years ago

I suppose you mean there's a conflict between authentication and verification: if developer requires verification in the authentication flow, an unverified user cannot authenticate due to being unverified, and cannot verify due to not able to authenticate.

To solve this dilemma, we have the Authentication Session mechanism. It represents an immediate state between unauthenticated and authenticated (i.e. user is provisionally authenticated, but additional actions is required to be truly authenticated). It is like a workflow with steps (and we have only MFA at the moment). We can add verification as one of the step, so that unverified user can perform verification as part of the authentication flow.

In context of OIDC, the entire Authentication Session exists only within the OIDC provider (i.e. the Auth UI), and Relying Party (i.e. web app/mobile app/etc.) would be aware of the access token & refresh token only. Verification is done within the Authentication Session.

chpapa commented 4 years ago

@louischan-oursky

Sign up and Login Screen

In that case, I recommend let's implement default mode for sign up screen. I can't promise in future requirements like list mode won't happen though... (maybe via some advanced templating?)

For login screen, can we implement a "guess logic" as follows? Not sure if it is entirely correct...

Let's say the login ID key configured are username, email1, email2, phone1

The login screen display one field with "username, email or phone no."

After it submit

  1. It call the login API to see if it match any of username,email1,email2,phone1`
  2. If the loginID doesn't have a password and requires another IDP (SSO, or SAML in future), redirect to the IDP
  3. If no username match at step 1, and if the username contain number only, jump to the similar screen Frank designed to complete the number in E.164 format
  4. If 3 also fail, it is failed.

Obviously the problem is we don't have a login API for username only... but maybe we should consider it now?

(Shit, I suddenly realize this is another rabbit hole we can't avoid) In fact, a login id that associates with another IDP. is it possible right now? Say if there is a user with LoginID but no password, is it even possible with current Skygear Auth architecture?

Verification

What if we treat verification steps of AuthUI as something "after" the authentication success? Is it practical and make things simpler? (it contradict with the "no success page thing")

The edge case is, if the users never finish the verification, the developers is responsible for displaying a UI to say his account is not verified yet; And maybe we need one more endpoint to let them "redirect the unverified user to complete the verification process"

But no matter the user is verified or not, we assume he completed authentication.

i18n

Great :)

louischan-oursky commented 4 years ago

Signup Screen and Login Screen

  1. It call the login API to see if it match any of username, email1, email2, phone1`

The login API requires both login ID and password. However the login screen only requires the user to enter login ID. Unless we introduce a new API for testing the existence of a login ID, we cannot perform step 1

Actually Frank's design is very similar to Google's. I just tested the Google behavior and it DOES report the existence of gmail or phone and report incorrect password.

Screen Shot 2020-02-05 at 10 58 30

Screen Shot 2020-02-05 at 10 58 46

However, it conflicts with our login API behavior. We only reports invalid credentials. Should we break this property?

Obviously the problem is we don't have a login API for username only... but maybe we should consider it now?

I guess you meant testing the existence of login ID?

In fact, a login id that associates with another IDP. is it possible right now?

It is impossible right now. Login ID are all from the first party (Auth Gear). The remaining login methods are Custom Token and OAuth. They do not have direct relation to Login ID.

Say if there is a user with LoginID but no password, is it even possible with current Skygear Auth architecture?

It is possible a user with login ID but no password. If the user initially signed up with Google, they have no password. Later on they can add login ID. But they never login. They have to trigger the forgot password flow to reset (or we should say set) their password. See https://github.com/SkygearIO/features/blob/master/features/329-identity-apis/design.md#adding-login-id-without-existing-login-ids

Verification

What if we treat verification steps of AuthUI as something "after" the authentication success? Is it practical and make things simpler? (it contradict with the "no success page thing")

The dilemma here is that the Authorization Code flow only issues one Authorization Code. We cannot consume this code to authenticate and then perform verification AND ALSO deliver it back to the application.

As Terry said, if verification is part of the Authentication Session, it is done BEFORE the issue of Authorization Code so does not suffer from the above problem.

The edge case is, if the users never finish the verification, the developers is responsible for displaying a UI to say his account is not verified yet; And maybe we need one more endpoint to let them "redirect the unverified user to complete the verification process"

Actually the user could never finish the verification after signup. The developer must check the verification status of the user. In this case, the developer would use SDK to trigger verification flow. Maybe we should not bundle the verification step at all?

Or it is two separate flows. The developer first opens Auth UI to authenticate the user. Then it checks the verification status. If verification is required, the application calls SDK to deliver the verification code and then opens Auth UI to verify the user. In the second open of Auth UI, the session is either from cookie for Web Application, or it is extracted from the native cookie storage into the WebView of Auth UI. I admit the UX is not optimal here.

chpapa commented 4 years ago

I guess you meant testing the existence of login ID?

Yes, that's (sort of) what I meant.

I think the API is not "testing the existence of login ID", instead it is "does this loginID exists and require another IDP?"

And this API should work like this:

Other requirements for this API:

@louischan-oursky Thoughts? I wrote the above more from a UX / business POV... I think what is really "missing" there is not ways to check if LoginID exists -- I won't insist the two steps username > password just due to that... but I think we need the two steps username > password process to handle the case when user don't have a password but need to login via an IDP.

Or it is two separate flows.

In your opinions, is it a better and simpler solution?

Actually, why can't we just send the verification email behind the scene, and not having the application to call the SDK at all for new users?

louischan-oursky commented 4 years ago

Login ID on Login Screen

After a offline discussion with Ben, the use case we want to support here is to let the user to enter an identifier and then let Auth UI / Auth Gear to discover the IDP automatically. For example, if the user enters user@gmail.com, the IDP is Google.

There are two well known SSO standards, Open ID Connect and SAML. Both of them specify a discovery mechanism.

Open ID Connect specifies a optional specification Open ID Provider Issuer Discovery. The spec includes an example of how it looks like. Unfortunately, many OIDC IDP have not implemented it yet, including Google.

SAML specifies Identity Provider Discovery Service Protocol. Session 2.4 specifies how the protocol works. Unlike OIDC, the discovery service does not take the identifier as input. This means to discover the IDP is unspecified. If Skygear were to integrating an external discovery service, the UI we provide should be a button saying "Use SAML" instead of asking for an identifier.

In short, if we insist on asking the user for an identifier, the IDP discovery has to be done manually by Skygear. When a given OIDC IDP implements Open ID Provider Issuer Discovery, we can drop our own implementation for that specific IDP.

Note that the discovery only works if the IDP owns the identifier. For example, Google owns all accounts ending with @gmail.com. However, many people register their Facebook accounts with their Google account. It is impossible to know the user wants to use user@gmail.com with Facebook as the IDP.

Probing of login ID

A configuration to turn off this API? For some strict system with security requirement of not possible to test if a LoginID exists

A user can probe the existence of login ID by performing a sign up. If we have a configuration to disable probing, then the configuration should also disable public sign up.

chpapa commented 4 years ago

@louischan-oursky so any thought on what's the behaviour of some existing software, that after typing in the email address, it redirects the users to the IDP? Is it just simply a setting mark the user's enforced to use IDP?

louischan-oursky commented 4 years ago

so any thought on what's the behaviour of some existing software, that after typing in the email address, it redirects the users to the IdP?

Keyclock has Identity Brokering. It has several modes.

The design of the login page of keyclock is shown in the below image.

https://www.keycloak.org/docs/6.0/server_admin/keycloak-images/identity-provider-login-page.png

It requires either (login id AND password) OR selecting a IdP.


Is it just simply a setting mark the user's enforced to use IDP?

Slack supports configuring who in the workspace must use single sign-on


To be prepared for the feature you proposed, I think a forward-compatible design should be a list of IdPs plus a single login ID field. Right now the login ID field does not do any guessing. But in the future we may augment its behavior when the feature becomes common.

|---------------------------|
| Login with Google         |
|---------------------------|
| Login with Facebook       |
|---------------------------|

              Or

|--------------------------------------|  |----------|
| Enter in your email or username here |  | Continue |
|--------------------------------------|  |----------|

Login with a phone number instead.
chpapa commented 4 years ago

@louischan-oursky Ummm okay. Can you put together another Feature Issue for what we discussed and what you planned here? Thanks a lot!

louischan-oursky commented 4 years ago

@kiootic @carmenlau

I tried to sum up what we have discussed in the video call and wrote my suggestions.


Constraints

The following constraints may be contradicting with each other.

Auth UI must be able to be hosted on its own domain (1)

It fulfills the use case of having https://accounts.google.com for authentication and https://drive.google.com for application.

Session of Auth UI are stored as HTTP cookie. The cookie is non host-only. The cookie is set on root domain. (2)

This allows the application to share the session of Auth UI.

The cookie must be host-only. Unknown subdomains must not able to read cookie. (3)

The developer adds the custom domain example.com. They assign https://accounts.example.com as the domain of Auth UI. On the other hand, another unrelated web server may be running on https://wp.example.com. If Domain of the cookie is example.com, then it is visible to https://wp.example.com. One may tempt to allow the developer to customize the cookie name to avoid conflict, but this does not solve the unintended visibility problem.

Auth UI eventually is OpenID Provider. The integration between Auth UI and Auth Gear should the same as that between other IdP and Auth Gear. (4)

This does not treat Auth UI specially in API level. However in implementation level, Auth UI must be treated specially.

Suppose the user "Sign in with Skygear" with email and password.

If Auth UI and Auth Gear are the same app, the user should have only one identity, the password identity.

If Auth UI and Auth Gear are NOT the same app, that is App A is depending App B as its authentication server, then

  1. In the database of App B (the Skygear App acting as OP), there is a new user and a new password identity.
  2. In the database of App A (the Skygear App acting as RP), there is a new user and a new OAuth identity.
  3. Note that the two users in has different user IDs.

Auth Gear is merged into Auth UI. The existing JSON API of Auth Gear will be implemented by Auth UI. (5)

The server side rendering part of Auth UI remains a traditional web application that does not require API key.

The session transport has several big changes.

  1. Header and cookie are no longer mutually exclusive. Cookie has higher precedence.
  2. The difference between cookie and header is whether refresh is auto or manually. If the session transport is cookie, the access token is auto renewed WITHOUT refresh token. If the session transport is header, the access token must be renewed manually. Manually means manually by the SDK.
  3. Auth UI has a new endpoint to authenticate a HTTP request. This endpoint is for integration with any gateway. The new endpoint looks at HTTP header Cookie and Authorization to determine whether the request is authenticated. If the request is authenticated, status 200 is returned and the family of x-skygear-user-id headers are included in the response. Otherwise status 401 is returned.
  4. A special endpoint is placed at the application domain which accepts a Token Response. The special endpoint uses the access token in the Token Response to invoke the endpoint in Point 3 to validate the access token. If the access token is valid, it returns the Token Response verbatim plus adding the Set-Cookie header to instruct the user agent to store the access token in cookie store.
  5. Any other gears (i.e. Asset Gear) can either look at cookie, header or x-skygear-user-id to authenticate the request. In case of Skygear Cloud, Asset Gear will be served in a separate domain so it will never read any meaningful cookie because it itself does not write cookie at all. So it either looks at header or x-skygear-user-id.
  6. Microservices look at x-skygear-user-id to authenticate the request. Nothing change.

The SDK only calls the Token Endpoint of Auth UI. There is no Token Request forwarding. However, out of the OIDC flow, it calls the special endpoint to replicate the access token in the cookie of the application domain. In this design, there is only one kind of session.

Contradictions and Resolutions

(2) contradicts with (3). (3) is flavored because it is more secure.

kiootic commented 4 years ago

Some of the constraints (4, 5) are more like proposed solutions? I think it's better to use words like 'must'/'must not' in the constraints.

Also, since it seems that we cannot satisfy all constraints simultaneously, we may want to indicate the priority of each constraints (i.e. is this a must, or a nice-to-have?).

chpapa commented 4 years ago

Is it a discussion or....?

I thought (2) was ruled out in my previous discussion with Louis...

carmenlau commented 4 years ago

Constraints 4, 5 look like proposed solutions to me too? And they are new ideas which are different from the drafted spec #411. So now we should have 3 approaches? Maybe we should rule out some of them and further discuss the possible solutions?

louischan-oursky commented 4 years ago

Please ignore my previous comment

Here I am going to propose a solution taking some other future features into consideration.


To fulfill the requirement of issue 419

We have the following implications:

  1. Auth UI and Auth Gear must be the same program/server that can be run as a single docker image.
  2. Skygear Auth should be served in a separate domain because cookie is domain-scoped. This means our current https://{domain}/_{gear} convention does not apply anymore. There is another issue about moving Asset Gear into own domain.
  3. Skygear Auth must conform to OIDC Basic OP profile to allow any third party RP to integrate. The third party RP integrates with Skygear Auth in the same they integrate with other OpenID Providers.
  4. We want to be able to not use Skygear Gateway. So Skygear Auth must expose an endpoint to turn Cookie: and Authorization: into the family of x-skygear-user-id headers. Gears and microservices should use x-skygear-user-id to authenticate the incoming request.
  5. We had an assumption that gears and microservices are served in the same domain. But now this assumption is broken by (2). We need a way to make the access token received from the Token Endpoint to appear in the cookie. It implies that the other domains must have an endpoint to take the access token from either header or body, validate it with the endpoint in (4) and set it in cookie if valid. To maintain compatibility, the microservices domain must have such endpoint automatically added when the app is deployed on Skygear Cluster.

Implications on session:

  1. The session created at the Token Endpoint is not the same as the one created at the Authorization Endpoint. When Skygear Auth has OAuth authorization, the session created at the Token Endpoint is associated with an OAuth authorization. An OAuth authorization is per user per client and can be revoked.
  2. Session transport is not preconfigured and the access token can appear in either Authorization: or Cookie:. However, cookie has higher precedence.
  3. Session transport affects how refresh is done. If session transport is cookie then the access token is refreshed WITHOUT the refresh token. Otherwise the session must be refreshed at the Token Endpoint with the refresh token.

How Skygear Auth owns the data? How do they interact with other instances?

  1. If Instance A is depending Instance B as its authentication server, the instances have separate data. The same natural person is represented as an user per instance. Suppose the user uses Google to sign up at Instance B, the end result is as follows:
Instance A Instance B
User ID a b
Identity A Skygear Identity with foreign ID being b A Google Identity

Breaking changes

  1. Auth Gear and Asset Gear are moved. The path /_{auth,asset}/ will become HTTP 404. This can be worked around by proxying https://myapp.skygearapp.com/_auth/login to https://accounts.skygearapp.com/login.
  2. The SDK will now have multiple endpoints to work with. Specifically, skygear.auth operates on the Skygear Auth endpoint, skygear.asset operates on the Asset Gear endpoint and skygear.fetch operates on the app endpoint. The developer can override the endpoint in case a custom domain is added for Skygear Auth.
  3. API client configuration has session_transport and refresh_token_disabled removed.

Changes on custom domain

  1. Support designating a custom domain to serve Skygear Auth, Auth Gear or the app. Currently it is always the app.