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

Rename expires in to expires at #688

Merged
merged 6 commits into from
Aug 10, 2023
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 MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@

- The properties inside the `user` object will now be camelCase instead of snake_case
- Removed the `type` property returned in the `Credentials` object in Android. Use `tokenType` instead.
- `Credentials` object in Android will return `expiresIn` instead of `expiresAt`
- `Credentials` object in iOS will return `expiresAt` instead of `expiresIn`
- `expiresIn` value will now return `expiresAt` value which is a UNIX timestamp of the expiration time.
- `max_age` parameter is changed to `maxAge` in `WebAuth.authorize()`
- `skipLegacyListener` has been removed in `authorize` and `clearSession`
- `customScheme` is now part of `ClearSessionOptions` instead of `ClearSessionParameters` in `clearSession`
Expand Down
22 changes: 3 additions & 19 deletions android/src/main/java/com/auth0/react/CredentialsParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ public class CredentialsParser {
private static final String SCOPE = "scope";
private static final String REFRESH_TOKEN_KEY = "refreshToken";
private static final String TOKEN_TYPE_KEY = "tokenType";
private static final String EXPIRES_IN_KEY = "expiresIn";
private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";

public static ReadableMap toMap(Credentials credentials) {
WritableNativeMap map = new WritableNativeMap();
map.putString(ACCESS_TOKEN_KEY, credentials.getAccessToken());
map.putDouble(EXPIRES_IN_KEY, credentials.getExpiresAt().getTime());
map.putDouble(EXPIRES_AT_KEY, credentials.getExpiresAt().getTime() / 1000);
map.putString(ID_TOKEN_KEY, credentials.getIdToken());
map.putString(SCOPE, credentials.getScope());
map.putString(REFRESH_TOKEN_KEY, credentials.getRefreshToken());
Expand All @@ -38,23 +37,8 @@ public static Credentials fromMap(ReadableMap map) {
String tokenType = map.getString(TOKEN_TYPE_KEY);
String refreshToken = map.getString(REFRESH_TOKEN_KEY);
String scope = map.getString(SCOPE);
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT, Locale.US);
Date expiresAt = null;
String expiresAtText = map.getString(EXPIRES_AT_KEY);
if(expiresAtText != null) {
try {
expiresAt = sdf.parse(expiresAtText);
} catch (ParseException e) {
throw new CredentialsManagerException("Invalid date format - "+expiresAtText, e);
}
}
double expiresIn = 0;
if(map.hasKey(EXPIRES_IN_KEY)) {
expiresIn = map.getDouble(EXPIRES_IN_KEY);
}
if (expiresAt == null && expiresIn != 0) {
expiresAt = new Date((long) (System.currentTimeMillis() + expiresIn * 1000));
}
Double expiresAtUnix = map.getDouble(EXPIRES_AT_KEY);
Date expiresAt = new Date(expiresAtUnix.longValue() * 1000);
return new Credentials(
idToken,
accessToken,
Expand Down
9 changes: 4 additions & 5 deletions ios/NativeBridge.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ public class NativeBridge: NSObject {
static let refreshTokenKey = "refreshToken";
static let typeKey = "type";
static let tokenTypeKey = "tokenType";
static let expiresInKey = "expiresIn";
static let dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";

static let credentialsManagerErrorCode = "a0.invalid_state.credential_manager_exception"
Expand Down Expand Up @@ -108,11 +107,11 @@ public class NativeBridge: NSObject {
let refreshToken = credentialsDict[NativeBridge.refreshTokenKey] as? String
let scope = credentialsDict[NativeBridge.scopeKey] as? String
var expiresIn: Date?
if let string = credentialsDict[NativeBridge.expiresInKey] as? String, let double = Double(string) {
if let string = credentialsDict[NativeBridge.expiresAtKey] as? String, let double = Double(string) {
expiresIn = Date(timeIntervalSince1970: double)
} else if let double = credentialsDict[NativeBridge.expiresInKey] as? Double {
} else if let double = credentialsDict[NativeBridge.expiresAtKey] as? Double {
expiresIn = Date(timeIntervalSince1970: double)
} else if let dateStr = credentialsDict[NativeBridge.expiresInKey] as? String {
} else if let dateStr = credentialsDict[NativeBridge.expiresAtKey] as? String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = NativeBridge.dateFormat
expiresIn = dateFormatter.date(from: dateStr)
Expand Down Expand Up @@ -185,7 +184,7 @@ extension Credentials {
NativeBridge.tokenTypeKey: self.tokenType,
NativeBridge.idTokenKey: self.idToken,
NativeBridge.refreshTokenKey: self.refreshToken as Any,
NativeBridge.expiresInKey: floor(self.expiresIn.timeIntervalSince1970),
NativeBridge.expiresAtKey: floor(self.expiresIn.timeIntervalSince1970),
NativeBridge.scopeKey: self.scope as Any
]
}
Expand Down
28 changes: 18 additions & 10 deletions src/auth/__tests__/__snapshots__/index.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,15 @@ exports[`auth Multifactor Challenge Flow should require MFA Token 1`] = `
]"
`;

exports[`auth OOB flow binding code should be optional 1`] = `{}`;
exports[`auth OOB flow binding code should be optional 1`] = `
{
"accessToken": "1234",
"expiresAt": 1672617600,
"idToken": "id-123",
"scope": "openid profile email address phone",
"tokenType": "Bearer",
}
`;

exports[`auth OOB flow should handle custom parameter 1`] = `
[
Expand Down Expand Up @@ -57,7 +65,7 @@ exports[`auth OOB flow should handle malformed OOB code 1`] = `[invalid_grant: M
exports[`auth OOB flow should handle success with binding code 1`] = `
{
"accessToken": "1234",
"expiresIn": 86400,
"expiresAt": 1672617600,
"idToken": "id-123",
"scope": "openid profile email address phone",
"tokenType": "Bearer",
Expand All @@ -67,7 +75,7 @@ exports[`auth OOB flow should handle success with binding code 1`] = `
exports[`auth OOB flow should handle success without binding code 1`] = `
{
"accessToken": "1234",
"expiresIn": 86400,
"expiresAt": 1672617600,
"idToken": "id-123",
"scope": "openid profile email address phone",
"tokenType": "Bearer",
Expand Down Expand Up @@ -121,7 +129,7 @@ exports[`auth OTP flow when MFA is not associated 1`] = `[unsupported_challenge_
exports[`auth OTP flow when MFA succeeds 1`] = `
{
"accessToken": "1234",
"expiresIn": 86400,
"expiresAt": 1672617600,
"idToken": "id-123",
"scope": "openid profile email address phone",
"tokenType": "Bearer",
Expand Down Expand Up @@ -166,7 +174,7 @@ exports[`auth Recovery Code flow should require MFA Token and Recovery Code 1`]
exports[`auth Recovery Code flow when Recovery code succeeds 1`] = `
{
"accessToken": "1234",
"expiresIn": 86400,
"expiresAt": 1672617600,
"idToken": "id-123",
"scope": "openid profile email address phone",
"tokenType": "Bearer",
Expand Down Expand Up @@ -216,7 +224,7 @@ exports[`auth code exchange for native social should handle unexpected error 1`]
exports[`auth code exchange for native social should return successful response 1`] = `
{
"accessToken": "an access token",
"expiresIn": 1234567890,
"expiresAt": 2907099090,
"idToken": "an id token",
"scope": "openid",
"state": "a random state for auth",
Expand All @@ -226,7 +234,7 @@ exports[`auth code exchange for native social should return successful response
exports[`auth code exchange for native social should return successful response with optional parameters 1`] = `
{
"accessToken": "an access token",
"expiresIn": 1234567890,
"expiresAt": 2907099090,
"idToken": "an id token",
"scope": "openid",
"state": "a random state for auth",
Expand Down Expand Up @@ -288,7 +296,7 @@ exports[`auth code exchange should handle unexpected error 1`] = `[a0.response.i
exports[`auth code exchange should return successful response 1`] = `
{
"accessToken": "an access token",
"expiresIn": 1234567890,
"expiresAt": 2907099090,
"idToken": "an id token",
"scope": "openid",
"state": "a random state for auth",
Expand Down Expand Up @@ -419,7 +427,7 @@ exports[`auth password realm should handle unexpected error 1`] = `[a0.response.
exports[`auth password realm should return successful response 1`] = `
{
"accessToken": "an access token",
"expiresIn": 1234567890,
"expiresAt": 2907099090,
"idToken": "an id token",
"scope": "openid",
"state": "a random state for auth",
Expand Down Expand Up @@ -821,7 +829,7 @@ exports[`auth refresh token should handle unknown error 1`] = `[a0.response.inva
exports[`auth refresh token should return successful response 1`] = `
{
"accessToken": "an access token",
"expiresIn": 1234567890,
"expiresAt": 2907099090,
"idToken": "an id token",
"scope": "openid",
"state": "a random state for auth",
Expand Down
8 changes: 7 additions & 1 deletion src/auth/__tests__/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ describe('auth', () => {
};
const auth = new Auth({baseUrl, clientId, telemetry});

beforeAll(() => {
jest
.useFakeTimers()
.setSystemTime(new Date('2023-01-01'));
});

beforeEach(fetchMock.restore);

describe('constructor', () => {
Expand Down Expand Up @@ -875,7 +881,7 @@ describe('auth', () => {
});

it('binding code should be optional', async () => {
fetchMock.postOnce('https://samples.auth0.com/oauth/token', {});
fetchMock.postOnce('https://samples.auth0.com/oauth/token', success);
expect.assertions(1);
await expect(auth.loginWithOOB(parameters)).resolves.toMatchSnapshot();
});
Expand Down
51 changes: 31 additions & 20 deletions src/auth/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import AuthError from './authError';
import Auth0Error from './auth0Error';
import { Telemetry } from '../networking/telemetry';
import { convertExpiresInToExpiresAt } from '../utils/timestampConversion'
import {
AuthorizeUrlOptions,
CreateUserOptions,
Expand All @@ -28,6 +29,7 @@
UserInfoOptions,
} from '../types';
import {
CredentialsResponse,
RawCredentials,
RawMultifactorChallengeResponse,
RawUser,
Expand All @@ -43,6 +45,15 @@
throw new AuthError(response);
}

function convertTimestampInCredentials(rawCredentials: RawCredentials): Credentials {
let expiresAt = convertExpiresInToExpiresAt(rawCredentials.expiresIn)
if(!expiresAt) {
throw Error('invalid expiry value found')

Check warning on line 51 in src/auth/index.ts

View check run for this annotation

Codecov / codecov/patch

src/auth/index.ts#L51

Added line #L51 was not covered by tests
}
const { expiresIn, ...credentials } = rawCredentials
return {...credentials, expiresAt}
}

/**
* Class for interfacing with the Auth0 Authentication API endpoints.
*
Expand Down Expand Up @@ -144,13 +155,13 @@
parameters
);
return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...payload,
client_id: this.clientId,
grant_type: 'authorization_code',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
);
}

Expand All @@ -176,14 +187,14 @@
parameters
);
return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...payload,
client_id: this.clientId,
grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
);
.then((response) => {
return convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
});
}

/**
Expand All @@ -194,13 +205,13 @@
*/
passwordRealm(parameters: PasswordRealmOptions): Promise<Credentials> {
return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...parameters,
client_id: this.clientId,
grant_type: 'http://auth0.com/oauth/grant-type/password-realm',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
);
}

Expand All @@ -222,13 +233,13 @@
parameters
);
return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...payload,
client_id: this.clientId,
grant_type: 'refresh_token',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
);
}

Expand Down Expand Up @@ -294,14 +305,14 @@
parameters
);
return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...payload,
client_id: this.clientId,
realm: 'email',
grant_type: 'http://auth0.com/oauth/grant-type/passwordless/otp',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
);
}

Expand All @@ -324,14 +335,14 @@
parameters
);
return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...payload,
client_id: this.clientId,
realm: 'sms',
grant_type: 'http://auth0.com/oauth/grant-type/passwordless/otp',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
);
}

Expand All @@ -356,13 +367,13 @@
parameters
);
return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...payload,
client_id: this.clientId,
grant_type: 'http://auth0.com/oauth/grant-type/mfa-otp',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
);
}

Expand All @@ -389,13 +400,13 @@
);

return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...payload,
client_id: this.clientId,
grant_type: 'http://auth0.com/oauth/grant-type/mfa-oob',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
);
}

Expand All @@ -422,13 +433,13 @@
);

return this.client
.post<RawCredentials>('/oauth/token', {
.post<CredentialsResponse>('/oauth/token', {
...payload,
client_id: this.clientId,
grant_type: 'http://auth0.com/oauth/grant-type/mfa-recovery-code',
})
.then((response) =>
responseHandler<RawCredentials, Credentials>(response)
convertTimestampInCredentials(responseHandler<CredentialsResponse, RawCredentials>(response))
);
}

Expand Down
Loading